Wednesday, October 31, 2007

Fasten Your Seat Belts! - Chances And Pitfalls Of Test Driving Your Development

Ten years ago I had a rendezvous with a beautiful girl, and at the end of the evening I gave her a ride home. Back than I thought playing the gentleman to be posh, so I opened the door for her. She slid with one elegant movement into her seat and I paced around the car and folded my wiry frame behind the steering wheel. I looked at her.

"Don't you want to start?", she asked and watched me curiously. "Um", I said, obviously always finding the right words at the right moment. "Um. - Not before you buckle up...". She frowned at me: "But I never buckle up". I replied "Well, if you don't buckle up, we're not gonna go anywhere tonight". "Oh come on!", she now somewhat furiously stated. "Nope!" I insisted eloquently, finally feeling her shield of stubborn resistance falter. It took a few seconds before she realized that I really wouldn't drive her home without her being properly protected from falling through the windshield and decomposing her pretty head by hitting the next best fireplug. So she buckled up.

Even back than I was so used to the secure feeling of the protective belt that just thinking of driving unbelted drove an uneasy quiver through my guts. This feeling is so strong that if I don't drive strapped when moving the car just a few inches there's always a sense of awareness that makes me want to fasten the seat belt immediately.

Today I felt exactly the same way while writing code.

The path of the test

At the beginning of the last iteration we identified a story that affected some legacy modules in our code base. When we recognized that the changes we needed to make would touch more code than we had thought, so we decided to try to test drive a part of the system from scratch to replace the tangled old code. So Richard, Reinhard and myself started to pair on the story alternately. Besides some private experiments with a Sudoku solver in Java this was the first time I was doing real full time TDD pair programming for a couple of days. Aside from some initial irritation and the constant realization that pair programming is hard to learn I was quickly pulled into the red-green-refactor cycle, as usual. But this time I held the pace for longer than ever. And was pulled into the cycle deeper and deeper. Write a test, make it work, look for redundancy. Write a test, make it work, look for redundancy. Write a test...

Today I wanted to quickly integrate the changed interface into an existing module. I didn't have a test yet. The cpp file was readily opened in my editor. Just a quick edit, nothing more than integrating this interface. A few simple edits. Only three lines or something. And suddenly a nagging question materializing in my head:

How can I make sure this works?

At this moment I felt like driving unbuckled. I felt unsafe. I wanted my cozy safety net back. Like an addict I went for the next test.

What use is a seat belt when you hit a tree at 200 MPH?

Since I'm the one driving the adoption of XP in our company, I wanted to try TDD for myself on a save playground to learn more about the ins and outs before applying it at work. Since Java has really nice tools for TDD, I started test driving a small Sudoku solver in Java. This was my first real test driven code and I often wondered about how nicely the test suite covered my errors. Spirited in the Agile fashion, I began with a really straight forward brute force implementation. Everything went a lot more smoothly than I had expected and after some coding I had a simple solution that needed over 90 seconds for one simple Sudoku.

After a while I wanted to optimize the runtime. So I introduced some caching variables. I struggled with the failing tests as my solution grew more and more sophisticated, but the tests helped me to get to a deeper understanding of the real problem. Finally I arrived at a point where the algorithm managed to work through 1400 Sudokus in less than a second. I was thrilled. And I wanted more. So I installed a profiling framework to find out where the next optimization sweet spot would be hidden. When I browsed the profiling data I realized that the real solver didn't even call the algorithm. So I had benchmarked a program that didn't solve any Sudoku at all.

At this moment I felt like hitting a tree with 200 MPH, suddenly realizing that it is not a good idea to drive that fast into a 90-degree turn on a wet street, even if you have a seat belt.

After the blood had returned to my head on it's way to my brain I implemented a test into the main program to check every solution with a simple algorithm before claiming to have solved anything. In the meantime I have a solution that runs 1400 Sudokus in 6 seconds on my core 2 notebook. I'm even quite convinced that I got the solution part correct...

Do I get my driver's license?

So, here's the lesson I learned on this journey on my path to the test:

  • Don't rely on your tests too quickly.
    If you want to heed the XP advice to "test everything that can possibly break", be aware that it's often the things of which you think that they can't break that finally break.

  • Use a healthy mixture of tests on all abstraction levels.
    Unit and functional tests are orthogonal - they cover different aspects of the code. But of course you'll already have a lot of unit and functional tests if you don't rely on your tests too quickly.

  • Buckle up!
    The unsafe feeling while trying to modify code without having a test was a very impressive experience for me. I know that from now on I'll fasten my code's seat belt.


  1. This is a great post. Thanks.

    What's funnier is that the Google ads, that also seem to know where my ISP is located, are all about local driver education and traffic school.

    Three things about seat belts.

    1. I learned to be an airline passenger before I learned to drive (and before there were mandatory seatbelt laws). After learning how much more comfortable (and safer) it is to keep an airline seatbelt fastened except when leaving my seat, it was second nature to do the same when I started to drive at the age of 26.

    2. The one time I had a problem with a passenger was when my son was late in his adolescence and decided to refuse to buckle up one day. The car was already in motion, so I ended the argument by hitting the brakes. He caught on quick and fastened his seat belt. It was really some sort of control issue, and I am not sure I handled that well (I also pointed out that him being unbelted was a danger to others in the front seat too, if we were hurtling about for some reason.) Anyhow, neither of us have forgotten that experience, although there may be more lessons to it.

    3. Some women, including my wife, have anatomical difficulties with some seat belts, especially the over-the-shoulder and down the chest sort. I can sympathize with their pulling the shoulder belt slack in that case.

  2. Hi Orcmid, thanks for leaving your thoughts. "Hitting the brakes" reminds me of my driving teacher's educational methods. I wonder if one could apply this to software development, though :-)

  3. Great post. You style of narrative and choice of analogies really tell the tale vividly and captures the sentiments of what a developer goes through. It's just three lines, how hard or bad could it be? Sometimes the prize is a ticket to the Deep Valley of Frustration.

    Really enjoy your blog.

  4. [...] I got test infected I'm somehow unable to write a single line of untested code without feeling uneasy. When I just want to write a tiny script containing a few lines of code in whatever text editor is [...]

  5. [...] test Driving your Development .... I know that from now on I&39ll fasten my code&39s seat belt. ... safety tips ... do? seat belt failure is very rare see [...]

  6. After examine a couple of of the weblog posts in your website now, and I really like your means of blogging. I bookmarked it to my bookmark website checklist and can be checking back soon. Pls try my web site as well and let me know what you think.

  7. trade [url=]Forex[/url].