It did not take long after
Agile died that TDD joined its party. If you havent noticed,
David Heinemeier Hansson put up quite a
rant against TDD on his blog leading to a lot of discussion - also on Twitter. Finally they ended up doing a live online discussion regularely featuring
Kent Beck,
Martin Fowler and David not (yet) involving the TDD advocate
Robert C. Martin aka uncle bob. If you haven't watched it live, here is the initial
30min discussion of the series on Youtube. I really recommend the whole series.
I think this topic and the ongoing discussion is very valueable to our craft because it is the kind of questioning and critical thinking that evolve what we do and how good we are at it. Even if we have a strong faith in something, we should not be afraid to question it, ever.
I get davids points, however i do not entirely agree with all of his concerns. I want to share my thoughts in this blogpost.
„Test induced design damage“
A good design is a design that makes the software easy to change. I think this is something we all agree about. While TDD generally puts a lot of good pressure on your design, it can still make the code hard to change if you apply a high level of isolation, lots of mocking, and a high test-granularity. In this case refactorings and other changes will force us to touch a lot of test-code also. So i've come to the conclusion that its best to apply an individual level of test-isolation/granularity that suit the current requirements. Complex and/or long-lived software might take much value of a strict TDD approach, while simple and/or short-lived software might take more value of a more pragmatic approach. I've happened to experience lots of applications that were so big yet simple that "collaborating-units-tests" with reduced mocking and integration tests were just perfect. The value of this approach was that it was very easy to change/refactor production code without touching test-code. Still, the tests provided 100% functional coverage. So i think that design damage is not induced by tests or tdd, but by bad decisionmaking. Testing is engineering. Look for advantages, make tradeoffs. Trying to minimize mocking can definitely pay off. The advantages of a high test-isolation-level/granularity are
- a very accurate fault-feedback,
- and that every part of the code is executed just as much as it had to, leading to a faster test-suite
„To Test first, or not to Test first“
The point is, you do not want to verify if the code is working manually. You'd have to do it way too often, and it would just take too long. You want to be able to fiddle with the code, and do small changes frequently, without having to try everything out manually. You want to do it automated, and the feedback should be instant. So i see no point in 1. writing code, 2. trying it out, and then 3. writing a test. Why not write the test in the first place? Also, we tend to be very flaccid on writing a test for something that we have found to be working, because we tend to become euphoric about our success very quickly which makes us tired of digging in details. Other than that, the actual writing of the test first forces us to think about the problem to an extent that makes us recognize details, that we hadn't yet thought of. These details are better to be known before we start writing production code.
„TDD is so widespread nowadays“
I was laughing when i noticed that there are actually people who believe that everyone does tdd nowadays. Sadly, TDD, or lets say developer testing is in fact unused and/or undiscovered in many places. I've happened to see it missed in programming education and also software companies. Sometimes, it was even unwelcome by certain customers. If you were using any kind of developer testing in these places, you were a pioneer. There is still plenty of work to do on this topic.
The bottom line is, automated developer testing is good. We need it. We were silly if we didn't. The question is just: "How?". And this is where engineering comes in.