There were some clear advantages to the TDD approach to writing. In particular, writing the acceptance test first made me focus on exactly what I was trying to achieve. In some ways this is similar to writing an essay where the title is some statement you have to argue for and against to prove or disprove the notion.
Breaking the review down into units was super useful, although this is something I would always do when writing anyway, as in most cases each unit became a paragraph. I also found myself refactoring as I realised a unit was doing too much, and I separated it into multiple units. For example I started out with a single unit called ‘Plot’, which had separate tests for facts about the plot, my opinion, and the ending. This was clearly violating the single responsibility principle and doing too much so I broke it down into 3 separate units.
Perhaps more useful was breaking each unit down into tests, which meant I had to focus on simply fulfilling the test criteria. It is a useful approach in a situation where you have a strict word count imposed. Maybe a journalist could use the TDD technique for writing an article? Strict adherence to this rule of simplicity means avoiding waffle. Certainly I could have been more strict about this here. However while I agree that simplicity is important in writing, it is arguably more important in code. Good unit tests mean nicely decoupled classes, whereas writing the book review I felt I wanted a common thread linking it all together.
The major downside to the TDD technique is that writing is incredibly subjective. How on earth do you prove you’ve achieved something that is different for different people? Without constantly being able to run the acceptance test and just assuming that it was still failing I was not able to develop in small increments. This made me appreciate how useful automated tests are, something I have perhaps taken for granted before now.
I felt like I was having to take some big jumps to get to the next test, which means my tests were not driving my design. How different is this from writing software? You still have to make a decision about what to test, what test to write, etc. As long as you are strict about keeping the implementation as simple as possible, the code is still driven by the test.
I worry that I have I been less creative because I worked in this way, as I was forced to write only what was necessary for each test. In some ways the restriction here may have helped me be more creative, as I had to think about the minimum I could write in order to pass the test. Similarly in software development, by writing the minimum code to pass the test we often write code we would not have otherwise considered. Moreover any creativity you may have lost in the initial development you can add later when refactoring. By this point you have a safety net of regression tests. This is something I don’t have without automated (or at the very least, repeatable) tests.
As I had no real idea where or how to start writing the rigidity of the TDD approach helped me get something down on the page. Likewise when test driving software the act of writing a test focuses what you are going to do and limits the scope. This can help you get started, but if you already have lots of ideas the rigidity may slow you down.
Dan North has been talking for a while about the trade offs you make when doing TDD (loss of initial speed versus reliability and simplicity of designs). He also advocates the “spike and stabilise” method. I wonder if this would be a better approach for writing. I don’t feel that the acceptance test helped me go faster, because there was not an easily repeatable way to run it. It is certainly useful to define your objective before you start so you know what you are trying to achieve. But without an objective way of knowing that you have achieved it, this can never truly drive your design.