Remember when in the first post of the series I said that we should write the requirements as tests before writing the code that implements it? but why is this important? what’s TDD anyway?
As you may have noticed, during the implementation of the requirements in the last post I always wrote part of the requirement before writing the implementation to make it pass, and then refactored the code a little bit by trying to generalize the algorithm and make it clearer to the reader. I was able to change the code and improve it because I Knew there was no way I could break something because the tests would warn me otherwise. Then, after I was satisfied with the refactoring I started again with another piece of requirement.
To put it in programming terms I was more or less following this algorithm:
|public bool IsImplementationComplete(List requirements)|
|Requirement current = requirements.First();|
|public void TddStep(current)|
TDD stands for Test Driven Development and was first introduced by Kent Beck in his game changing book Extreme Programming Explained. This technique is similar to Test First in the sense that you translate in tests your requirements before writing any implementation for them. By following this methodology you guide the development and the design (to some TDD means Test Driven Design) of your program with the help of the feedback that you get from the tests.
Like any methodologies it has some rules you have to adhere in order to be able to say that you actually practice TDD. These are Three Rules of TDD (follow the link for a very good explanation of the rules) :
- Never write implementation without tests that prove that it’s correct;
- Write the minimum amount of test that makes the test suite fail;
- Write the simplest implementation to make the test pass;
By following this rules you enter in a short feedback loop in which you are always sure of the behavior of the program you are writing. You can either have all you implementation working or just one failing test and, as Bob Martin’s article says, almost never run the debugger.
This feedback loop is commonly described as the Red Green Refractor loop because you write a test that have no implementation and which obviously fails (Red), then you write just the smallest implementation to make it pass (Green) and then, when you know the program is working, you start to Refactor and start all over again.
At every refactoring step you take you can run your test and verify that your application is still working the way it was before starting the refactoring phase. And if suddenly you get an error, you know it was introduced by your last change because you never made too many changes without testing them. This means you are just a few seconds away from the last change you did and you remember exactly what you did and why, and in the worst case you can just undo the change loosing just a few seconds of work, instead of hours.
When you work following the red green refactor loop you find yourself constantly concentrated in implementing the next requirement, the next, and the next again. It’s easier to enter in a state of Flow when you could continue writing code without interruption. Personally I find it addicting, when I program following TDD I need to use the pomodoro technique to remind me to take a break every 25 minutes or so.
The flow state is facilitated by the fact that, as I said before, you rarely launch the debugger. Instead, you keep checking all your code after every change you make.
Another great advantage is that by following TDD you end up with a pretty easy to understand and easy to verify documentation of your code. Think about the last time you had to maintain a piece of code: you probably had to go through a bunch of methods trying to understand. If you working in TDD has the nice side effect of leaving a trail of tests that exercise your implementation in every possible way so, if you need to understand how a method works you just need to look up the tests that verify that method.
Last but not least is that by having all your code tested, you are protected form introducing bugs in working software. Picture this, how many times have you changed a piece of functionality and found out later on, most probably when your code is already in production, that you broke some other feature of your program? This wouldn’t happen if all your code was covered by a comprehensive suite of tests, because you would discover the regression right after you launch your tests.
So to summarize the main advantages of using this methodology are:
- You stay more concentrated on your work;
- You almost stop using the debugger;
- Tests become a living documentation that help you understand other people code;
- High test coverage means regression free changes;
What other advantages do YOU know or think TDD can have? what common objections do you have or have encountered while talking about it with your peers? let us know in the comments and well cover them in a future post.
All this is great but…
If you are thinking that you can’t start using TDD because you work with complex objects or classes you should read the next article of the series when we will cover what Test Doubles are so stay tuned
Author: Daniele Pozzobon
Daniele is an aspiring software craftsman and Scrum Master with more that ten years of experience in the software industry.
He is currently working on amazing solutions in the manufacturing industry helping with the development of a DevOps culture.
He constantly annoys his friends by talking about software and is passionate about Agile methodologies and DevOps, which gives him more opportunities to talk annoy his friends even more.
When there are no friends around to annoy, he blogs on CodeCleaners and in his free he time loves go hiking with his wife and two daughters.