An Idea for Tracer Bullets
My favorite software development related book, The Pragmatic Programmer, has a section in it where it mentions tracer bullets. The tracer bullet system they describe really reminds me of the scaffolding system that Rails made popular. It’s sort of a loose structure that gives you something to play with but that really needs to be fleshed out for your finished application. The idea behind using a tracer bullet, or scaffolding, is to have that basic structure to build with and help avoid the ‘blank page’ problem (writers and programmers both know that a blank page is the most difficult thing to write from). So scaffolding is useful, and what Dave and Andy remark as tracer bullets I’m going to call scaffolding for this piece. I would like to introduce a different idea for what tracer bullets are, and how they can help you focus on good Test Driven Development (TDD) and battle the problem of forgetfulness due to complexity.
If you’ve ever worked on a new system or a larger refactoring of an old system, you’ll have noticed that you get into a sort of groove with what you’re doing. You look at the big picture and you start making your modifications. Something comes up though where you change a method signature and you have to adjust all of the places that use it, which maybe makes you rethink some basic designs and causes another smaller refactor or something during your larger one. Eventually when that’s all done you go back to what you were originally doing. You’re testing all the way which is good, but eventually you get to a point where you stop and say “I’m done”. Or at least that’s the idea. Often it comes out more like “Am I done?” and you wrack your brain trying to think if you remembered to put everything into place or are you leaving out some small bit that’s going to cause a bug later on. If this has never happened to you and you don’t understand what I’m talking about, you may stop reading.
The main problem seems to be that you have this grand idea at the beginning, and you know pretty much all of the parts that you’re going to have to modify to make things work, you just loose track of what you’ve done and what you haven’t done. Now you can make a paper ToDo list at the start and check everything off, and that’s a viable method. However I would submit that you should utilize your best programming tool right from the start to keep track of your progress: your tests.
When you first collect your refactoring (or basic design) idea, you should know many of the places that you’ll need to modify in order for it to function. Create unit tests for each of these major ideas. These tests should fail with an error message relating to what the idea is and a note that it isn’t actually implemented yet. As you start to refactor, replace these tests with the actual tests for that piece of functionality. You won’t be fully removing the tests (just by having those tracer bullet tests to start with means there’s something that needs to change and those changes need to be tested), but you’ll be adding real tests for your changes to them. When all of your tracer tests are replaced, you should know that you’ve covered everything that your design required.
That doesn’t mean additional testing shouldn’t be done, there are often times areas that need to be modified or added that you did not originally envision. However, it should be a good start to tracking down those areas that need work. It should also prevent you from forgetting any of those key areas that you thought about originally but lost track of during the hectic course of development.
Tracer Bullets in this sense are really just empty failed tests that provide guidance as to what you need to work on. They’re not real tests, but they’re placeholders for where tests should be in the future. They act as a guide to help you figure out what you should be working on next. In addition, since you need to modify those failed tests for your build anyway, it should encourage you to work in a more test driven way by writing your tests first. Since you’ll look at your list of failed tests as your “ToDo” list, it will encourage your first action being to change those tests to something useful rather than a paper ToDo list which encourages you to jump into writing the application code before your tests.
Anything that keeps us more organized and removes unnecessary burdens to our mental flows is a helpful device for a programmer. Being able to utilize any technique that will increase your likelihood to properly test your application code is also a great benefit. This is just an idea I’ve been pondering for some weeks and I’m sure it’s not the only one for combining your design and testing in an up front mannor. If anyone else has any suggestions or practices that they use, please feel free to let me and others know what they are.