Wednesday, June 8, 2011

Test Second Development

Let me start off by stating that I'm a big fan of test-first development. I think that a (the?) major benefit of writing unit-tests is the fact that the first person to use a new API is the developer herself/himself. By first writing tests against the API before it has written you increase the likely hood of creating a unable, testable and bug free code. Test-first development is valuable even if you never ran any of the unit-tests that you wrote. The purpose of this post is not to extol the virtues of test-first development but to share a scenario where I feel it may be  better to not write the unit-tests right away.

Several weeks ago I started to work on a simple command line utility. Nothing fancy but just something to scratch an itch that I've had for a while. I had a vague idea of what I wanted it to do but hadn't quite worked out all of the details. Additionally I wasn't sure how the utility would involve. Finally I was writing the utility in Google Go, which I have done a bit of development but I certainly haven't played with it long enough to fully think in the language. In short I simply didn't know what I was doing and I knew it would be some time before I fully understood the problem I was trying to solve. I started to write the code and neglected to start by writing unit-tests. After some time of hacking on the utility I finally got to the point where I had a working prototype and I finally understood the problem. At that point I reviewed the code of my program and I realized that I had (not surprisingly) got the architecture of the program wrong. I figured out the right architecture of the program and started on the refactor. During the refactor the majority of the original code and internal API's was radically changed. If I had written any unit-tests they would have been discarded as the code and API's they would have tested simply did not exist in the refactored program. I could have preserved end-to-end tests but not any unit-tests. During the refactor I wrote unit-tests and I now have a program that has good unit-test coverage. I'll call this development process "Test Second Development". I'd like to propose the following criteria for when test-second development may be appropriate.

  1. You don't understand the program you are writing.
  2. You don't understand the language you are writing the program in.
  3. You will have the luxury of refactoring the program once you understand it, and before it "ships".
  4. You're disciplined enough to write unit-tests when you do your rewrite/refactor.
In other words I think it may be OK to delay writing unit-test when you are writing a true *prototype.

My thoughts on test-second development are still immature and evolving, but I thought I'd jot them down for future reference. In my case I don't think that I would have gained any benefit to using test-first development and I can definitely see how test-first development would have slowed down the discovery process.

* If you are writing code for your job and anyone else will know about your project, then I really doubt you will ever write a prototype. As soon as someone sees or hears about your project they'll want to ship it. I once worked for a company that shipped a simple utility that I had written to aid in testing my code. I only found out that they had shipped it after my manager came and talked with me about the utility and told me that I needed to pretty up the GUI. When I told him that it was a testing utility and was never meant to be shipped he told me that since it was shipped we'd have to support it. I started prettying up the GUI and started on a new testing utility. The new testing utility had a big banner across the front stating that it was for internal testing only. I later learned that calling testing tools something like "The enema tester" was a good strategy for ensuring that internal testing tools never got shipped.