First of all, what’s Test-Driven Development (TDD)?
Test-driven development (TDD) is a software development process that relies on the repetition of a very short development cycle: first the developer writes an (initially failing) automated test case that defines a desired improvement or new function, then produces the minimum amount of code to pass that test, and finally refactors the new code to acceptable standards.
Doesn’t sound too bad right?
In fact it is a pretty useful principle and shares a lot of similarities with a concept called “Design by Contract” made popular by Eiffel Software and the Eiffel programming language.
In a nutshell you can use “Design by Contract” and “Test-Driven Development” to specify expected behaviour before you actually implement it. This allows you to later verify whether what you’ve built actually adheres to the original intention/specification/contract.
So what’s the problem?
There’s nothing wrong with the concept of Test-Driven Development. It is one of many super useful tools available to software development teams.
I believe the problem is that Test-Driven Development (along with its cousin Behavior-Driven Development) became a victim of its own success. It is slowly being turned into a cargo cult.
Instead of using the concepts of TDD where they make sense on a case by case basis it is now often regarded as the one true way to write code. Without caring whether there is enough return on investment to justify it.
A pragmatic approach to testing
Instead of aiming for 100% test coverage and obsessing about unit tests I think we should aim for a healthy mix of software development best practices.
Don’t get me wrong, I don’t oppose automatic testing. I don’t even oppose TDD in general.
I just believe that the dogmatic idea that every line of code should be written in a TDD-way is harmful to our industry. Just like the dogmatic worshipping of Object Oriented Programming as the silver bullet was an overreaction.
TDD can be very useful when you aim to implement system behaviour that needs to follow a certain well defined format or protocol. TDD is also a great tool for drafting parts of your code base that you know will be refactored immediately after they are written.
In other more innovative cases like new feature development it might make sense to avoid everything that could add unnecessary inertia like tests or excessive use of documentation or types (see Dart and other languages with optional type annotations).
All these things can be added later once you’ve verified that the feature you’ve built is valuable and will actually stay in the code base.
Sometimes a few high level acceptance tests added after the fact can be a great trade-off compared to countless TDD unit tests.
In the end we need to make sure that the technical decisions we all make are rational decisions from a business point of view, else we waste resources that could be put to better use.
TDD is a useful concept. We all owe Kent Beck a lot for introducing us to it. It’s great to have it in your developer toolbox. Use it wisely and appreciate its elegance when it is the right tool for the job.
Don’t get trapped by dogma.
If you found this post helpful you might want to follow me on twitter where I tweet about Software Development & Product Management ☺
Also make sure to check out Blossom an Agile/Lean Project Management Tool I’m currently working on ☺