Test-driven development is a great way to ensure that your code is of a good quality. It forces you to think about how your code should work before you write it, and then lets you test it rigorously to make sure it actually does what you want it to.
There are many benefits to using test-driven development, however, there are also some drawbacks to using this approach. Let's try to find out what are the benefits and drawbacks of TDD.
As you probably know, I work at one of those rare companies, which are following extreme programming practices. On a daily basis, we pair with each other and write our software using test driven development. In this post I wanted to share my professional opinion on and experience with TDD.
Before anything, what is TDD in the first place? Test-driven development is a style of programming which uses tests to "drive" (or guide, or direct) the implementation. If you want to see how it works - soon I am planning to publish a video on my youtube channel demonstrating TDD.
While there're more than one schools of TDD, it all started when Kent Beck has formulated what is known "three rules of TDD"
Those are three rules of TDD:
- Write production code only to pass a failing unit test.
- Write no more of a unit test than sufficient to fail (compilation failures are failures).
- Write no more production code than necessary to pass the one failing unit test.
As was mentioned, there are more than one schools of TDD but the main rule is to write test first.
TDD encourages really small implementation steps (sometimes in a matter of minutes) and quick feedback loops.
So let me start from the most obvious benefits and then move to the less obvious benefits of TDD.
First of all, by using TDD, you get high and meaningful code coverage.
In the typical TDD loop, you don't write a production code unless a failing test which requires this production code to exist, which makes the quality of the production code and the tests themselves better. Which of course leads to the bug density decrease.
You make fewer bugs!
You don't need mutation testing or things like that to know that your tests are actually testing something - because you saw them failing.
Because of the high and meaningful test coverage one usually has confidence in the code they write. They know they can release sooner because the whole code was unit tested! And, depending on what school of TDD you're using, the code could have other types of test as well, such as acceptance or integration level tests.
Unit tests you created can be a very good documentation for the code. For example, when a new developer starts to work on a new peace of software, they can start looking at the unit tests instead of the code itself and have a very good idea of what the logic of production code is and what it was designed to do.
Some people would say that using test driven development is really complicated, because the frameworks that they use are not well suited for the unit tests and they would require integration tests or even system level tests. And that's actually another benefit of test driven development.
Test Driven Development gives you a very good architecture and code quality feedback, because there is correlation between how easy it is to test code using unit tests and how modular and granular your code is.
And because usually TDD practitioners avoid making any big changes to the code between writing unit tests, the chances you will have to debug because you don't know what is going on are way smaller.
Now to the most surprising and least known benefit of using test driven development.
By using test driven development, by actually following short red-green-refactor loops, your brain gets lots of positive reinforcement, which makes programming a very enjoyable activity. It is actually really satisfying to see how you go from nothing at all to something that works and not only something that works, but is well tested.
Just think about writing your production code for several hours, and then debugging and testing it, feeling really tired only to learn that now you need to write unit tests for the code you wrote! This can be really frustrating.
With test driven development, you don't get this level of dissatisfaction. Instead, you get a constant positive reinforcement
So, what are the drawbacks of test driven development if any? I should be honest with you, I am a TDD fan and practitioner and it was not easy for me to find real and significant drawbacks for the driven development. I tried hard, so I came up with something really interesting, which I believe can surprise even experienced developers.
First of all, test driven development requires training. It is not so easy to start using TDD if you don't know how the mechanics works, and that would require some additional training, even for the senior engineers.
There is also a confusion between different schools and styles of test driven development. Sometimes when people are arguing that test driven development is good or bad, they actually argue not about test driven development as a phenomenon, but about a particular school of test driven development, and then all have different purposes and were designed for different contexts.
Another potential drawback of using TDD is, while test driven development would help you to come up with a working algorithm, it usually is not guaranteeing you to come up with an efficient AND/OR effective algorithm. So, learning algorithms and data structures would still be very important if you want to write well crafted software.
TDD can actually slow you down and make you come up with a WORSE solution. Let’s have a look at this Mars Rover Kata solution. This is the shortest, simplest (though not easiest) solution to the Kata I have seen, and surprisingly it has less potential failure points. TDD solutions would be 3-4 times more complex, with more failure points, and would actually take longer to implement. So to get it straight - in some cases it would be better NOT to write tests in advance and the end result would be objectively better.
By the way, if you want me to make a video about Mars Rover TDD kata - please drop me a comment.
So taking all this into account, Test driven development may be overkill for throw-away code or for the code that you're not actually aiming to maintain. Proof of concept, some one time routines - this sort of stuff. That's where you probably wouldn't want to use test driven development.