Prologue

When a business struggles with maintaining code quality, quite often its first impulse is hiring people to test the product manually: clicking on the screens of a web/mobile app, probing APIs with curl, etc. While in some cases it is absolutely necessary, usually it is best to shift the paradigm and approach testing as the integral part of software development.

What’s wrong with manual QA?

At first glance, manual quality assurance seems like the most straightforward and simple thing to do. It is rather cheap (since manual QA engineers are usually not as expensive as the developers) and seems to be doing its job: some bugs get caught before they are shipped to production, and raw features are returned to the developers for polishing. But when looking at the process in more detail, we can see some obvious problems that have no solutions.

Not keeping up with volume

As the codebase grows, the amount of stuff to test grows as well. With each new feature, more and more labor is required to ensure that everything is working correctly. Since it is practically impossible to hire a new QA engineer per each N features, the only remaining choice for a company using manual QA is to skip testing of some parts that are allegedly not affected by the code change. While this might sometimes work out with well-designed systems that provide enough component isolation, it is almost guaranteed that some important integration is going to be forgotten and remain untested eventually.

Being unreliable

Us humans are extremely error prone. Even when the test scenarios are well defined (which they usually aren’t), when the QA notes in the ticket are detailed and thorough (which they aren’t again), and when the people doing the job are focused and well-rested (you won’t believe it) — it is always possible that someone skips a test step that leads to a bug. And it gets only worse when most work is repetitive, since it eventually turns our auto-pilot on and limits our thinking capabilities significantly.

Being slow

Manual QA is extremely time-consuming. Not only does following the actual test cases cost a significant amount of time — even more time gets wasted on communication between the developer and the responsible QA engineer. Describing the implementation in QA notes, getting additional details through asking questions, passing the reproduction steps: everything comes with a time toll. Also note that almost nobody is a perfect communicator, and each interaction might cause misunderstanding, costing even more time.

What to do instead

The obvious (and the right) answer to the problems listed above is automation. A CI job doesn’t mind running the same test over and over — with precision and instant feedback for the developer in case of a failure. But it is not enough that we simply take the same approach as we had, by just replacing manual QA engineers with people who develop automated tests. Just like with DevOps (actual DevOps in its original form, not the bullshit market name for engineers with CI and Kubernetes skills) which merges the development and operations silos, it is crucial to break the wall between development and quality assurance as well.

Since both developers and QA automation engineers (or SDETs) write actual code, it is only logical to merge the actual job functions and finally make the developers responsible for the quality of their product. It is a must for a good developer to be able to demonstrate that their code actually works by implementing tests: not just the unit tests, but the integration and end-to-end tests as well. After all, it is the developer themselves who knows best how their feature works and how to test it. There is not a single good reason to delegate testing to someone else and, even worse, to blame someone else for poor code quality (as it often happens with QA engineers).

Epilogue

Please do not get the idea that I am advocating for dropping the QA engineers altogether. Knowing what to test and how to actually test it is an invaluable skill, and for me personally, this always has been the hardest part of the development process. There are also some very specialized areas of testing (like penetration, UX, or accessibility testing) that are relatively difficult to learn and automate.

What I suggest instead (for both current developers and QA engineers) is to participate in each other’s activities as much as possible and to learn from each other, up to the point when a QA engineer is able to develop a feature themselves, and when a software engineer is able to cover their code with tests. It doesn’t mean that everyone should be equally good at everything — just that everyone should be working on a common goal in the most effective way (read: automated and not passed so much between different people).

Be inquisitive, learn to both code and test, and always advocate for quality. That’s what makes a great engineer and a great product.