The not-so-obvious benefits of Test Driven Development
I've been working my way very rapidly through Extreme Programming Adventures in C#, from Ron Jeffries and I've noticed some very subtle benefits to the way Ron does things. I mentioned in a previous blog post that Ron's book has a narrative style that leads you hand in hand with him as he applies eXtreme Programming practices to a new project, while simultaneously learning C#. It's the geek equivalent of "And now ladies and gentleman, for your delectation, a triple forward somersault blindfolded over a pit of crocodiles without a safety net".
The thing you notice almost as soon as Ron starts to write code is that he uses Unit tests not just to test required functionality in methods, but also to try out ideas. For example, if I were struggling with putting an XML feature into my application, Ron would advocate writing a test that explores the functionality of .NET's XML support, like this [Test]public void FindNode() { string xmlConfig = @"<courier><machines/></courier>"; XmlDocument configDoc = new XmlDocument(); configDoc.LoadXml( xmlConfig ); XmlNode node = configDoc.DocumentElement.SelectSingleNode("machines"); Assert ( node != null ); Assert ( node.Name == "machines"); }
It's not immediately obvious but this is a very cool way of working for a number of reasons. First up, obviously it saves you all the hassle of creating hundreds of dinky throw away test projects. Second, using nUnit to test your own assumptions about how the part of the framework you are learning works gives you a very visual, and immediate feedback loop which is a great aid to learning. Third, despite all the online help that Microsoft kindly provided with Visual Studio.NET, it can still be hard to find just the right code example for the job. Since you most often create these little technology tests as I can them to solve a specific problem in your code, you start to build up a repository of research right there in your app solution with fully tested working code that shows just how to get things done. I can't count the number of times now that I have cut and pasted code from the technology tests into the main project classes (and then refactored it of course, to remove duplication) when I've run up against a wall. The final benefit of this way of working is that these technology tests, if you add them to a single TestFixture class in chronological order provide a wonderful insight into the train of thought your went through when building the application. I don't know just how useful that is yet, but it sure is a neat free win.
On a different note, its really easy to adopt misconceptions about test driven development. The most common of these is that you spend so much time developing the tests at front, compared to the amount of time that it takes to get the feature in question working, that unit tests would appear to be detrimental to the progress of your work. Don't you believe that one for a second. Sure, writing the actual feature code usually burns a lot less time than the unit tests around it, but would that be the case if the unit tests weren't there. Think about it for a second. Your unit tests, written before you added the funtionality itself, test the code and provide valuable insight during the feature's development as to what's not working and why. Without that feedback I can't help feeling that you'd get the feature code written just as quick, but debugging it could degrade into a nightmare. When that happens there always a resistance to move on and just record the bugs for later. Unit tests get you to the same point in time that you' d normally say "It's good enough" with code that is perfect and not a compromise based on time.
By far the biggest benefit of unit tests though, in my opinion, has nothing to do with checking that the code works. It has to do with providing a safety net that enables refactoring and code evolution. We all meet those points in writing an app where something needs to be restructured. Whether you call it optimizing, refactoring, hacking or tweaking, the fact remains that without a set of unit tests underneath your code base you have no real idea whether or not all your hard work is actually damaging the application as a whole. Those unit tests that were so tedious to write when you were itching to add a new piece of functionality really come into their own when you need to tweak stuff. They tell you when you screwed up and where. That's invaluable.
Unit Tests then are an investment on three levels; your knowledge, your application's stablity, and your applications future, unplanned and unimagined evolution.
9:44:39 PM
|