People give many reasons for why they do Test-Driven Development (TDD). The benefits I get from TDD, and thus my reasons for practicing it, are given below, in order of most important to least important. The order is based on whether the benefit is available without test-first, and the ease with which the benefit is gained without a test-first approach.
1. Executable specification
The first step in building the correct thing is knowing what the correct thing is (or what it does). I find it very difficult to be confident that I’m building the correct thing without TDD. If we can specify the expectations of our system so unambiguously that a computer can understand and execute that specification, there’s no room for ambiguity or misinterpretation of what we expect from the system. TDD tests are executable specifications. This is pretty much impossible without test-first.
I also believe Specification by Example, which is necessary for TDD, is a great way to get ‘Product Owners’ to think about that they want (without having to first build software).
2. Living documentation
The problem with most other forms of documentation is there is no guarantee that it is current. Its easy to change the code without changing the natural-language documentation, including comments. There’s no way to force the documentation to be current. However, with TDD tests, as long as the tests are passing, and assuming the tests are good and valid, the tests act as perfectly up-to-date documentation for and of the code, (from an intent and expectation point of view, not necessarily from an implementation PoV). The documenation is thus considered ‘living’. This is possible with a test-after approach but is harder than with test-first.
TDD done properly, i.e. true Red-Green-Refactor, forces me to focus on one area of work at a time, and not to worry about the future. The future may be as soon as the next test scenario or case, but I don’t worry about that. The system gets built one failing test at a time. I don’t care about the other tests, I’ll get there in good time. This is possible without test-first, but harder and nigh-impossible for me.
4. As a design tool
This is the usual primary benefit touted for TDD. My understanding of this thinking is thus: in general, well-designed systems are decoupled. Decoupling means its possible to introduce a seam for testing components in isolation. Therefore, in general, well-designed systems are testable. Since TDD forces me to design components that are testable, inherently I’m forced to design decoupled components, which are in general considered a ‘better design’. This is low down on my list because this is relatively easy to do without a test-first approach, and even without tests at all. I’m pretty confident I can build what I (and I think others) consider to be well-designed systems without going test-first.
5. Suite of automated regression tests
Another popular selling point for TDD is that the tests provide a suite of automated regression tests. This is absolutely true. However I consider this a very pleasant by-product of doing TDD. A full suite of automated regression tests is very possible with a test-after approach. Another concern I have with this selling point is that TDD is not about testing, and touting regression tests as a benefit muddies this point.
Why do you do TDD? Do you disagree with my reasons or my order? Let me know in the comments!