Reflections on TDD

Reflections on TDD


Test-first or test-driven driven development (TDD) is an approach to software development where you write the tests before you write the program. You write a program to pass the test, extend the test or add further tests and then extend the functionality of the program to pass these tests. You build up a set of tests over time that you can run automatically every time you make program changes. The aim is to ensure that, at all times, the program is operational and passes the all tests. You refactor your program periodically to improve its structure and make it easier to read and change.

It is claimed that test-first development improves test coverage and makes it much easier to change a program without adversely affecting existing functionality. The tests serve as the program specification so you have a detailed but abstract description of what the program should do.

I deliberately decided to experiment with test-first development a few months ago. As a programming pensioner, the programs I am writing are my own personal projects rather than projects for a client with a specification  so what I have to say here may only apply in situations where there’s no hard and fast program specification.

At first, I found the approach to be helpful. But as I started implementing a GUI, the tests got harder to write and I didn’t think that the time spent on writing these tests was worthwhile. So, I became less rigid (impure, perhaps) in my approach, so that I didn’t have automated tests for everything and sometimes implemented things before writing tests.

But, I’m not giving up on TDD because of the (well-known) difficulties in writing automated tests for GUIs. I’m giving up because I think it encourages conservatism in programming, it encourages you to make design decisions that can be tested rather than the right decisions for the program users, it makes you focus on detail rather than structure and it doesn’t work very well for a major class of program problems – those caused by unexpected data.

  • Because you want to ensure that you always pass the majority of tests, you tend to think about this when you change and extend the program. You therefore are more reluctant to make large-scale changes that will lead to the failure of lots of tests. Psychologically, you become conservative to avoid breaking lots of tests.
  • It is easier to test some program designs than others. Sometimes, the best design is one that’s hard to test so you are more reluctant to take this approach because you know that you’ll spend a lot more time designing and writing tests (which I, for one, quite a boring thing to do)
  • The most serious problem for me is that it encourages a focus on sorting out detail to pass tests rather than looking at the program as a whole. I started programming at a time where computer time was limited and you had to spend time looking at and thinking about the program as a whole. I think this leads to more elegant and better structured programs. But, with TDD, you dive into the detail in different parts of the program and rarely step back and look at the big picture.
  • In my experience, lots of program failures arise because the data being processed is not what’s expected by the programmer. It’s really hard to write ‘bad data’ tests that accurately reflect the real bad data you will have to process because you have to be a domain expert to understand the data. The ‘purist’ approach here, of course, is that you design data validation checks so that you never have to process bad data. But the reality is that it’s often hard to specify what ‘correct data’ means and sometimes you have to simply process the data you’ve got rather than the data that you’d like to have.

So , I’m going back to writing code first, then the tests.   I’ll continue to test automatically wherever it makes sense to do so, but I won’t spend ridiculous amounts of time writing tests when I can read the code and clearly understand what it does. Think-first rather than test-first is the way to go.

  1. I’m sure that TDD purists would say that I’m not doing it right so I’m not getting the real benefits of TDD. Maybe they are right. But I have never found zealots to be very convincing.