TDD is hard

Test-driven development is not really as easy as they say. Maybe nobody said it was easy, but I got that impression.

I’ve been trying to do TDD for about two years, and at first I thought it was horrible. Mostly because it forced me to break dependencies to the degree that my code was no longer nice and self-contained the way I used to like it.

Then I fell in love, or became infected, whichever you prefer. I realised that the dependency-breaking is a good thing, and that it’s pretty incredible to have automated regression tests for all your code. I tried to test-drive everything, and valued testing in isolation higher than anything else.

Now I have come to the conclusion that I’m not very good at testing behavior. I tend to test every possible detail, control flow or error condition I can come up with, and this causes the tests to lock the code beyond modification.

I’m trying to find a middle ground where I lock down interesting behavior and choose units at the right level of detail to begin test-driving. Maybe then I can get the extra boon of having the tests tell me more about what I need to build, rather than just making it more difficult to change existing code.

I think it comes down to experience in OO design. I doubt a beginner using TDD will automatically produce better designs than a more experienced developer who is not test-driving.

This just goes to show what I’ve suspected for a while: agile practices are generally very well distilled best practices, but they do require significant prior experience on behalf of their users to be beneficial.

Or maybe I’m just a slow learner.

Annonser

The Recursive Context Adapter idiom

Sometimes it makes sense to allow a method a default value for one or more of its parameters. Sometimes, because the parameter is a complex, user-defined type, it doesn’t make sense to hard-code its construction sequence in the parameter list. Consider this example:

void Widget::Resize(Rectangle* pRect /* = NULL */)
{
  static const Rectangle default(100, 100, 100, 100);
  if (pRect == NULL)
  {
    // Use default
    pRect = &default:
  }

  // Do resize
}

I’m not too happy with this code. There’s some unbalanced quality to it that I don’t care for. I ran into a case like this once, and came up with this technique:

void Widget::Resize(Rectangle* pRect /* = NULL */)
{
  if (pRect == NULL)
  {
    // Use default
    Rectangle r(100, 100, 100, 100);
    Resize(&r); // recurse!
  }
  else
  {
    // Do resize
  }
}

It’s so simple and succinct, and can actually be used for various other flow-of-control adjustments besides parameter defaults. Based on some contextual circumstance, you can change some aspect of the flow, and run the method again. This is a strictly controlled way of using recursion that actually helps readability. I didn’t think that was possible.

It seems to be generally applicable, so I’ve decided to dub it the Recursive Context Adapter idiom. The name alludes to the fact that it’s recursive, and that it adapts the context of the method before running it for real.

First post

Big day!

Not only did I decide today to stop using Internet Explorer in favor of Mozilla Firefox. Apparently I also started blogging.

So far I’m happy with Firefox, and undecided on writing for public consumption. We’ll have to see how it goes.

Until next time.