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.
- You don't understand the program you are writing.
- You don't understand the language you are writing the program in.
- You will have the luxury of refactoring the program once you understand it, and before it "ships".
- 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.