My programmer nightmare, or improving your code skills with tests

Some of you are probably smiling and saying that’s nowadays everybody understands the importance of tests in writing code, but you’ll be surprised how many programmers don’t write tests, or write minimum lines of testing code in order to show they do write tests.

So, if you know everything about tests — skip this article — you won’t discover anything new in lines below…

I have been working for a small high tech company for more than a decade. As any company we have a lot of good days and some “bad” days.

Engineers who worked here from the beginning had built a nice application with very progressive architecture — for those days. Time was running, some people left, some new ones came. Every person was working exactly as he wished: adding lines of code, classes and functions… A lot of lines of code. Good and bad.

And then we started facing problems.

When somebody tried to add new feature, he found himself struggling with old code. Most of changes in the new code caused additional bugs in the old code. New features added into old flows, started to behave unpredictable and again caused new bugs enrollment. 
So what was the solution — you all know, if something works — don’t touch it. Great! 
A lot of new features defined new flows (even if the difference between the old one was just a few lines), new classes with minimal re-use and so on. Since all our code was in same project, lines of code were growing and growing.

At this point I decided that source of the problem is huge size of project. Nice, so let’s divide it. I started my poor attempts to do this. Oh My God!
I didn’t succeed to advance even a little. After every small change I found myself doing limitless amount of “after-shock” tasks: fixing bugs, combining code classes to improve re-use, implementing design-patterns… and caused new bugs, discovered bugs which after long time turned to features (nice, huh?) because customers knew only such behaviour (“We don’t have bugs — only features” — sounds similar). And with all this stuff — “Show Must Go On”. New features were added (in the same way as before and so on) — endless nightmare.

It was really depressing. 
I started to talk to my colleagues and found that they had the same problems (by the way I realized another important thing — talk to your colleagues, or use Agile and retrospective to find what was wrong, or both. Don’t wait too much time).

And we found a solution — as you can guess — writing tests. Really?! Yes, and running it for every, even minor change. I must admit, it wasn’t so simple. Maybe, you are not familiar with this, but if you haven’t written tests before, it takes time to understand how and what to test. You write code and then try to write tests, but find that code is not so “testable”. Coupling, duplicated code and so on.

But there was a positive side-effect. The understanding that your code needs to be suitable for tests helps to write the code itself better: decoupled code, divided in more suitable pieces of code, even improve reuse, writing mocks and finally when you add/change code, you can run tests and find that something was wrong a long time before you finish your feature and it comes to QA (and goes back to you, delaying releases and features).

After getting some experience, we started to write tests for legacy code. And again, the result was not only adding coverage for legacy code, it caused us to change the existing code according to all advantages I mentioned above. Of course, not everything was perfect. Not always the amount of tests was enough. Some use-cases were missed. In some cases when tests failed, we had to refactor the already written code.

The life became much better. But still we had a lot of things to improve, and not really realized how. We thought about changes in architecture, in working flows and so on (all of this, still should be done).

And at this moment one of our engineers found the magic. This magic was called TDD — Test Driven Development.

You can find a lot of definitions and improvements by searching the world wide web, but below the “understanding”, I realized for myself:
find design issues (and understand flows you should write) during very early stage. 
write testable (and again, small, much more defined and clear) code.
understand much more possible pitfalls and edge cases, adding negative and positive tests — according to design. 
drill down from high level to more and more specific problems and their solutions.

It is really awesome and exciting. Now I really feel being a Software Developer :)

And small note before the end: to make your product good, working and stable, you still need someone to define the product and requirements, human power and hours to write automation tests (either with the help of automation engineers or developers themselves). Writing tests is very, very important part of developer cycle, but of course not the only one.

Good luck,
Mikhail Grinfeld