Monday, 1 October 2007

TDDing a new feature into the existing code

Suppose you have managed to find out the conditions that lead to a crash. How do you fix it in a TDD fashion? Or, how do you add a new feature to the existing code?

I usually try to resist using the existing code at first. Instead, I modify my production code so that the new conditions take a new path of execution. For example, I assign a certain ID to some object that is part of my test setup, then in the production code I check for this ID, and if it fits, I take the new path. This way I make sure that all my previous tests go to the old path, and since I don't touch the old path code, they will pass for sure.

Next, I force the new test pass as usual. I don't even need to check the other tests -- they are not affected.

Now comes the interesting part. I'm refactoring the new path as usual, watching the new test, but I'm trying it the way it looks "similar" to the old path. I might factor out a new method that looks like the one that's been used by the old path. Sometimes I could even use an old method. If the new test breaks, the old method needs to be modified. Or, I could modify the old method (now I should also watch the old tests). If it's too complicated to incorporate the new behavior, I repeat the same trick: split the path into two, and try to make it one in smaller steps.

With each small step, the difference between the two paths diminishes, so at the end we have a common path of execution, and we can remove our initial split.

No comments: