Thoughts on TDD (After almost 20 years)

I used to think I was good at programming (1976–1999), then I started doing Test-Driven Development. Since then I discovered that I make mistakes regularly. TDD puts your mistakes in your face, immediately. With this kind of feedback and a focus on small steps you can prevent many defects in you code from getting past you to your co-workers, QA or your customer. — For me, it means very little time hunting down mysterious behavior, a.k.a. bugs!

The best you, a programmer, can do with TDD is get code to do what you think the code should do. This simple concept, a confirmation that your code is doing what you think it should do, is very powerful. Your system works on purpose. Have you ever fixed a bug and broke something else? That other thing only worked by accident (offsetting defects allowed the other thing to work). In a way you are blindfolded and have no idea that there’s a problem.

I like dealing with code with my eyes open.

Defect prevention is only the most obvious benefit. The next benefit is that as you change your code (either because you have a better design idea, or your customer asks for a change, or you discover how you were wrong in the first place) you have a regression test suite that holds your code steady, notifying you of any unintended consequences. TDD helps you when you have to make changes, and you will have to make changes.

TDD by itself does not mean good design. I wish it were so, though it can lead down a path to better design. If your code is hard to test, it’s not a test problem; usually it is a design problem. TDD provides early warning of design problems as well as a subtle pressure on you to make the code better. TDD works best with cohesive modules that are loosely coupled. This is not automatic. You need to understand the subtleties of SOLID design, DRY (don’t repeat yourself) and DAMP (descriptive and meaningful phrases) and to be able to envision better code constructs.

Here is a partial list of TDD benefits:

  • TDD helps prevent initial defects.
  • TDD gives fast feedback on what your code is doing.
  • TDD produces a set of regression tests (almost for free, once you learn TDD).
  • TDD supports you when you change your code, letting you know when unintended things happen.
  • The tests are the detailed documentation for the code under test — this documentation does not lie. When it deviates from the code it tells you.
  • The tests act as the detailed long term memory of what the code is supposed to do.
  • Oh yeah! TDD is fun. The feedback is fast. You get satisfaction every few minutes as you get your code to dance.

Now for the downside…

  • TDD takes time to learn.
  • You’ll probably make a mess in your code and tests.
  • Tests have to be maintained — (Though it is worth it. Not having the tests makes the product harder to maintain.)
  • Good tests and good design take time to learn.
  • Applying TDD takes judgement. Not every line of code is a candidate for test driving. (Not really a downside, but you do have to think. So if thinking is something you want to avoid, you might want to go into a different field.)

    Most cited TDD misconception

  • TDD takes too long — Editorial comment: Compared to what? It may take some time to learn, but I’ve found that debugging takes a lot longer.
  • My life as a programmer is much better with TDD.

    Unfortunately, I cannot convince you about the value of TDD. Though, you can convince yourself. The only way I know for you to convince yourself is by trying it. Take the time to experience TDD. Pair with an experienced test-driven developer. Take a training course. Find a friend to experiment with.

    There are many seasoned TDD practitioners that started as skeptics. Actually I do not know of any that did not.

    This blog originated as an answer to this Quora question: What are your thoughts on Test-driven Development? What are the pros and cons?