Test Driven Development

TDD, sometimes considered the same as test-first development, is encouraged by a lot of experienced developers. The technique has its merits; writing code to exercise an API right at the start of development can be a good way to guide the shape of the API for usability.

There are several potential risks with TDD that need to be considered.

  1. Is TDD accessible to the junior members of the team?
  2. Is concentrating so many types of work into a single process actually helpful?
  3. Is TDD as efficient as we can get?
  4. Does TDD encourage writing all of our code by hand, rather than automating some?

TDD tries to bring design, coding and testing together into a very tight loop. For people that are able to understand the different skills to employ at each stage and switch between these three very quickly it can be very productive. However, a lot of people on a team can find this constant context switch very hard and it can be very mentally draining. As a result, the risk is that they will fall back to concentrating on only a small subset of the skills they are to be employing, letting the others slip. Ask yourself how easy is it to identify when this happens, and how detrimental that might be to the system.

TDD is based on the three step Red-Green-Refactor process in a tight loop. However, this by its nature is not entirely efficient, as refactoring is a rework of code already written.

It is sometimes said that the three steps do not carry the same weight; often, the first two steps get a lot of focus, and the third is rarely done. Since it is the refactor step that is intended to keep the codebase maintainable and fit for future change, then people who fall into this trap are hurting the team's future, but it may not be apparent at the time. This can lead to the build up of unintended technical debt.

There is an unwritten assumption in the work of most TDD practitioners: that some design has already taken place before the TDD process is started. We cannot write any tests before first understanding at least a little about the subject matter. However, what the practitioners often do not make clear is their position on how to carry out this up front design. Generally it is believed that they expect it to be very lightweight, and probably not formal.

There is a lot of merit to the idea of delivering simple solutions. However, the jury is still out on whether this short term benefit might be at the cost of more consistent velocity in the long term. In my experience, a team who designs their deliverables up front and then shares ideas through design reviews are likely to make better judgements about whether there are design decisions that will be beneficial for the future, and at what expense they can be introduced.

The other thing I would say about TDD is that testing is hard to get right - really hard. A lot of people focus effort on testing at the wrong level, and encourage more testing than is actually valuable. I recommend Ian Cooper's talks entitled "TDD, Where Did It All Go Wrong?" for a good discussion on this subject. YouTube

Testing has huge value in the right circumstances, and TDD has merit, but it is very hard to do correctly and can often drive unwanted artefacts in the code. Like other techniques, it is not perfect, and is likely to be replaced with something better.