As professional developers our role is to produce high quality software for our clients. To achieve this goal we must make sure that our application meets the requirements defined by the business analysts and works as expected, without side effects.
To achieve this, you should rely on a full automated tests suite. And to make sure that this tests collection is complete and cover all your code base you can practice Test Driven Development (TDD).
TDD relies on repeating a short development cycle where tests are writing before production code. This process can be defined by the 3 following rules.
- Don’t write any production code until you have written a failing unit test.
- Don’t write more of a unit test than is sufficient to fail or fail to compile.
- Don’t write any more production code than is sufficient to pass the failing test.
By following these rules you can implement the required needs step by step. And by writing the tests first you also have to think from a caller perspective, you are a client of your own code.
With this paradigm shift, you have to think of what is actually needed in order to complete the case you are working on and nothing more. It is helpful to avoid any unnecessary over-engineering phase that might happen in the early development phase. This way you can follow the YAGNI (You Aren’t Gonna Need It) and the KISS (Keep It Simple, Stupid) principles, you only code what you need, nothing more.
TDD makes you write your tests suite at the same time as your production code. This allows you to be able to refactor the code easily, and you will do refactoring all along the way.
Refactoring is even one of the 3 phases of TDD: Red, Green, Refactor. You start by writing a failing test (Red), you write code to make it pass (Green) and you refactor the code to make it cleaner (Refactor). And of course you make sure that the tests still passed after the refactoring before writing a new failing test.
By practicing TDD, you consistently work with a safety net, if something is broken you know it right away!
Leading to better design
The TDD approach forces you to write testable software, therefore it is likely that the code will be less coupled than if it was written straight away without tests first.
A less coupled application is easier to maintain and easier to extend with new behaviors. This way you can improve your code base by adding advanced programming patterns during refactoring phases when you actually need them.
Due to this fact, TDD is sometimes decomposed as Test Driven Design instead of Test Driven Development. Yet to achieve better design when using TDD it is important to know programming patterns and programming principles (e.g. SOLID in oriented object programming).
One of the benefit of having a full tests suite for your production code is that it can work as documentation for it. By browsing the tests of your APIs the caller knows how to use it, how to instantiate the classes and what the expected outputs are for the available methods.
And this kind of documentation is always up to date since it is bound to the associated code it tests, if the code is updated so are the tests otherwise it fails.
More about TDD to come
When writing these lines I am still new to TDD and to be honest I don’t practice it every time, especially when working on legacy project (which would not have become legacy if developed with TDD or proper code coverage at least…). But I strive to follow the TDD rules when adding new behaviors to an existing project covered with tests.
I really want to learn more about this practice and this is why I work on increasing my TDD skills with some side projects. I will share the experience gained from these projects in a near future on this blog.
At the moment I am convinced that using TDD is very helpful to produce high quality software in a concise way. It helps me thinking of the exact behavior I want/need for my program. I like the fact it gives instant feedback and allow constant refactoring without having the fear of breaking anything.
See you next time!