Bloggo back to the blog
A Software Skills Roadmap for Testers-->
How Should Testers Learn How to Write Code?
In a blog elsewhere, ‘The testers and coding debate: Can we move on now?’ , I suggested that:
- Tester programming skills are helpful in some situations and having those skills would make a tester more productive
- It doesn’t make sense to mandate these skills unless your organization is moving to a new way of working, e.g. shift-left
- Tester programming skills rarely need to be as comprehensive as a professional programmer’s
- A tester-programming training syllabus should map to required capabilities and include code-design and automated checking methods.
If testers want to learn how to code, what do we need to think about to make this happen? How do we help testers who need and want more technical capabilities?
How should testers acquire coding skills?
As I also said in the original article , I am not an expert in the teaching of programming languages or computer science in general. I have not studied the many writings of experts in this field who, needless to say, tend to be academics. But I am trusting an international team of academics who have . They reviewed the research literature in this area (101 sources were cited). Their concluding remarks include this:
“We conclude that despite the large volume of literature in this area, there is little systematic evidence to support any particular approach. For that reason, we have not attempted to give a canonical answer to the question of how to teach introductory programming.”
So, with the belief that I am on reasonably safe ground, I will suggest that most commercially available programming courses are inappropriate for teaching programming to software testers and that a different approach is required. The programming skills taught to testers should be driven by the need to improve capabilities and must include fundamental code design principles and automated checking methods.
In the remainder of this article, I want to propose an approach to teaching non- or partly-technical testers enough programming skills to support broader testing-related capabilities.
Don’t think skills, think capabilities
The polarising question, ‘to code or not to code’ is unhelpful. It makes much more sense to ask about capabilities. Let us ask, ‘what software-related capabilities does a tester need to do their job?’ Well, of course, it depends on the job. Here is a non-definitive list of tester capabilities that some testers (and their teams) might find useful in different situations (prefix each with ‘ability to…’):
a) Read and understand the flow of control of code and fundamental algorithms
b) Construct, execute and interpret tests using a unit test framework (in a TDD, BDD context)
c) Construct, execute and interpret tests using a GUI test tool (in a system testing context)
d) Challenge and discuss with developers the coverage, value, thoroughness of unit tests
e) Write simple utilities to extract, filter, sort, merge, generate test data from a structured database and non-structured XML, HTML, CSV, plain text sources
f) Use or adapt existing libraries to construct tests of networked devices, web servers, services, mail, FTP, terminal servers
… and so on.
I should explain why I used the term capability, rather than competency. In some circles, competency implies having qualifications, being certified etc. So to avoid being drawn into that debate, I’ll use the word capability from now on. However, the word capability is no less of a challenge. The SEI’s Capability Maturity Model (Integrated)  is also a powerful and polarising force. CMMI is a certification industry in its own right. Even so, capability is the most appropriate term for current purposes.
Mapping technical skills to new capabilities
The capabilities (or team/project requirements) above will be familiar to most testers. Usually, non-technical testers will consult their development colleagues, or bring in a test automation specialist or tool-smith to help out. Alternatively, they might have to acquire the skills to do the technical tasks themselves. What technical skills are required for each capability above?
1. All of these capabilities require a fundamental understanding of how code is written and experience of writing code in any language
2. Capabilities b-f require skills in a selected language
3. Capability b requires knowledge of one unit test framework
4. Capability c requires knowledge of a GUI test tool or library
5. Capability d requires a deeper insight into code construction and the significance of coverage
6. Capability e requires knowledge of standard libraries (to access DBs, parse XML, HTML, to use regular expressions)
7. Capability f requires knowledge of libraries that require additional technical or architectural knowledge (to drive network traffic or drive HTTP/web, mail servers etc.)
Several attempts at programming (or software engineering) competency levels have been published. One commonly referred to is here  but it focuses on aspects of programming, systems architecture, software engineering skills. It looks more like a software engineering syllabus than a competency roadmap. For now, let’s park the idea of a competency or maturity scheme.
Now, the capabilities above are not in any particular order. They might be required in a variety of contexts and the skills profile for each capability differs. Although the fundamental knowledge required to write code can be taught, the way you become more proficient is to take on increasingly ambitious assignments that require deeper knowledge. It is your ambition and willingness to learn new things that determine how far you progress as a programmer. Let me illustrate this with reference to the libraries you might need to understand to build some functionality.
In one respect, it’s just the libraries you use that varies, but as you tackle more advanced problems the skills you need become more sophisticated. Here’s one way of looking at the levels of capability. Read as ‘ability to do/use…’:
1. Basic programming that requires no special library support
2. Libraries that form part of the core language
3. Libraries mentioned in language cook-books that support activities outside the core language e.g. more advanced algorithms, messaging, integration with social media etc.
4. Research, evaluation, selection and use of libraries that are less well known, not well documented perhaps, not mentioned in books etc. e.g. data analysis, real-time, leading edge products (everything was leading edge at some time) etc.
5. Creation of your own generic libraries, where no usable library yet exists.
It is reasonable to expect that a junior programmer should be capable of level 3, an experienced programmer level 4. A programmer needs the programming language skills but also the ability and confidence to make their own choices. Testers need to understand how the progression from beginner to gain confidence and some independence (what I’ve characterised as level 3 above).
What and how do testers need to learn?
All this talk of capabilities is fine but the questions a tester needs answering are:
- I need a capability. What skills do I need?
- How do I acquire them?
I am going to suggest that firstly, the motivation is the need to acquire some tool or utility to improve your capability and help you in your job. It is all very well learning to write code by rote to code some dummy programs that are of little value outside the class. But if, at the end of the course, you are left with some working code that has value, you have the beginnings of a toolkit that enhances your capability and that you can evolve, improve and share.
The best way to learn a particular aspect of programming is to have working examples that you write yourself or samples that you are provided with, that you can adapt and improve to suit your own purposes. Of course, in a training course, some example code that performs a useful function has to be limited in scope to allow it to be usable for teaching. It might also have to be a suboptimal solution to the problem at hand. For example, it might not use the most sophisticated libraries or the most efficient algorithm etc. Inevitably, the offered solution to a set problem can only ever be one of many possible. Other real-world factors outside the classroom might determine what the ultimate solution should look like.
Of course, you also need a safe and assistive programming and testing environment and a good teacher.
Existing courses will not do
Almost all commercial programming training courses aim to teach the basics of a selected programming language. They focus almost entirely on the syntax of the language so what you learn is how to use the fundamental language constructs. Now, this is fine if you are already a programmer or you want to recognize the elements of code when you see them. But they don’t prepare you very well if you are a beginner and want to perform a real-world task:
- They don’t teach you much about good design or good (and bad) programming practices or styles
- If the language is object-oriented, it’s unlikely you will know how object-oriented design works (even if you know how to create and use objects)
- You will learn a lot of language elements that you might never use, or not need for some time to come
- Testing your programs is almost certainly not given much attention in the syllabus
- You may not have written any programs that are useful.
Programming classes for testers need to address all these aspects.
A roadmap for learning
What I’m proposing here is a set of design principles for programming training for testers. In a future article, I’ll suggest a possible course structure that has a specific set of capabilities in mind.
Pragmatic course design principles
A set of course design principles explain the thinking behind the Road Map and the content of specific courses. The word ‘client’ refers to the tester or the employer of the testers to be trained.
The course will specifically aim to teach people through example and practice to write code to perform specific tasks. The aim is not to learn every aspect of the selected language.
Pragmatic, Not Perfect
The course exercises, examples and take-away solutions will not be perfect. They may be less efficient, duplicate code available in pre-existing libraries, they might not use objects – but they will work.
All Courses Begin with a Foundation Module
The first, foundation module will cover the most fundamental aspects of program design and process and the most basic language elements. All subsequent modules depend on the Foundation module.
Content Driven by Demand for Capabilities
The course topics taught (the philosophy, programming language elements) will be sufficient to meet the requirements of the exercisesthat meet the requirements of a capability.
A Language Learning Process is Part of the Course
Because the course will not cover all language elements or available libraries, there will be gaps in knowledge. The course must allow you to practice how to find the right language construct, useful libraries and suitable code samples from other (usually online) source so you are not lost when you encounter a new requirement.
A Scripting Language Should be the Default
Where the client has no preference for a particular language as the subject for the course, a scripting language (Python, Ruby, Perl etc.) would be selected. The initial goal must be to learn the fundamentals of writing software in an easy-to use language. Popular languages like C++, C# and Java have a steeper learning curve. However, if your developers write all software in Java, for example – it is reasonable for the testers to learn Java too (although Java might not be the easiest ‘first language’ to learn).
Integrated Development Environments (IDEs)
IDEs are valuable resources for professional programmers. However, initial course modules would use simple, language sensitive editors (Notepad++, Gedit, Emacs etc.) Use of a specific IDE would be the subject of a dedicated course module.
Open Source Wherever Possible
To avoid the complications of proprietary licensing and to facilitate skills and software portability, open source language interpreters/compilers, test frameworks and language editors should be used.
Minimal Coupling Between Course Modules
The focus of each module is to build a useful utility and for each module to be independent of others (which might not be required). Of course, for modules to be independent, some topics will be duplicated across modules. Courses must allow the trainer to skip (or review) the topics already covered to avoid covering the same topics twice in different modules.
And with that long list of principles, let’s sketch out how the structure of a course might look.
The Structure could comprise a set of modules including an initial Foundation module and other modules that each focus on building a useful utility. A tentative course consisting of four modules might comprise:
1. Foundations of programming in the selected language
2. A text file searching and pattern matching utility
3. A simple HTTP Website driver
4. A simple Web services driver.
This four-module course is just an example. Although the Foundation Module is quite generic and should give all students a basis to write simple programs and make progress, it could be enhanced to include more advanced topics such as Regular Expressions or XML Processing or Web site messaging, for example.
The overall theme of the example course is the testing of web sites and web services and manipulation of the data retrieved. Obviously, courses with a different focus are likely to be required. For example:
- Database: Manipulation of data in relational technologies to manage, extract, generate, validate data (this would require a primer in relational databases and SQL)
- Unit Testing: Use of a Unit test framework to test classes, components and systems
- GUI Test Automation: Use of a proprietary or open source test execution tool or framework to drive desktop, web or mobile applications.
- Data Analysis: Use of data analysis libraries (In the case of Python these could be NumPy, Pandas, Matplotlib etc.)
- Big Data: Manipulation of data in NoSQL (not only SQL) technologies to manage, extract, generate, validate data
- … and so on
Of course, the precise content of such courses would need to be discussed with the client to ensure the course provider can meet their requirements.
In this paper, I have suggested that existing commercial programming courses tend to be focused on teaching the entirety of a language and are aimed at experienced programmers wishing to learn a new language. Testers need a differently focused course that will teach them a valuable subset of the technology that provides specific capabilities relevant to their job. Programming courses for testers need to be designed to support this somewhat different requirement.
A set of guiding principles for creating such courses is presented and a course description, for testing web sites and services through APIs, offered as an example. Other, differently focused courses would obviously be required.
This is a work in progress and comments, criticisms and suggestions for improvement are welcomed. I’m interested hearing ideas from other people who are thinking along similar lines (or not!)
1. Paul Gerrard, The testers and coding debate: Can we move on now?, http://www.ministryoftesting.com/2014/02/testers-coding-debate-can-move-now/
2. A Survey of Literature on the Teaching of Introductory Programming, Arnold Pears et al., http://www.seas.upenn.edu/~eas285/Readings/Pears_SurveyTeachingIntroProgramming.pdf
3. CMMI Institute, http://cmmiinstitute.com/
4. Sijin Joseph, Programmer Competency Matrix, http://sijinjoseph.com/programmer-competency-matrix/