Joan Antoni Morey
When dealing with a problem, wanting to fix a bug, refine an algorithm or refactor part of the code, it is important to know what is the expected result and what is the current status. Either via TDD or not, these two concepts have to be clear before you start writing code. Otherwise, we will find ourselves lost, improvising and even generating code that will not serve the purpose in question.
Having controlled these two concepts, we are going to delve into the TDD philosophy (Test Driven Development).
It is important to be familiar with the concept of "Test" and why you should start testing (if you don't already). If these are new concepts for you, I recommend that you read my previous article first Why you should start testing
As its name suggests, it is about developing guided by tests. In other words write the test first and develop later. It is a cycle in which the test is used as a validator for when the objective is met without going beyond what is necessary or doing manual tests with each change that we test.
The TDD mantra is:
First of all you have to write the test as if the functionality was already developed with the expected result. At this time, when no code is developed yet, the test will fail. That's good, don't worry about it at this point.
Then you have to start with the development but step by step. The point is to write the minimum amount of code needed to succeed the test, even it is not fancy, and don't write an entire block of code before you run the test again.
Once the test passes, you have to refine and refactor the code. This same test helps you with the process and keep it working, as in the GREEN step.
Nowadays this is the way we are used to proceed, outside of the TDD philosophy, where we write all the code that we think is going to be necessary for it to work.
Basically we currently develop the entire solution in our head and dump it all into code. This is how it is usually done. On the other hand, with the TDD, since the test is what tells you when it is enough for everything to work, you unload much of this mental load that comes with developing the entire solution upside down and write it down. That is why it is important to run the test with every few steps that we advance to make sure we don't write more code than is strictly necessary, since, having well defined the result expected in the test, once this succeeds, it's over.
On the one hand we have the pros of why you should use TDD, such as:
On the other hand we have the cons of the TDD:
In practice, TDD could be used in most cases, but we are going to define three large groups:
By implementing a new feature, whether it's a pure unit function or a set of features, it helps you accomplish your goal.
When you want to fix a bug it is better if you first establish a test to reproduce the bug and then develop the solution. This way you don't have to reproduce the error manually or through a complex set of functionalities.
When you decide to apply a refactoring to a block of code, it is vitally important to first write the tests that take into account what's up to now. Thus with each refactoring you can see if what was already working is still working. Otherwise you will end up with a failed refactoring by leaving the performance worse than it was, even if the code is pristine.
The TDD methodology has several benefits, such as mental download and confidence in the developed code.
On the other hand, it has drawbacks, such as, for example (and the most accentuated), changing the way of approaching the problem. As we have mentioned, we are used to starting to write code like crazy when we have an idea and we develop it entirely in our heads or, worse, we improvise.
In either case, we can make the mistake of over-elaborating the solution, taking more detours than necessary, and ending up with more code than necessary.
There are several scenarios where the TDD is useful: