Friday, September 15, 2006

 

The Power of DBC

I hadn't changed any code since my last successful test run so I wasn't expecting an error. I was puzzled when the debugger reported a stack overflow. Within minutes I realized the problem. In an object like:

MY_CONTENT

parent: MY_CONTENT

the reference to parent was set to Current. Obviously, some of my new content was being imported improperly. I felt panic rise in my stomach. My content import code is complex and hadn't changed in a while; I had no idea where to look for the problem. The panic quickly gave way to relief when I realized it was just a missing invariant. I added:

invariant

valid_parent: parent /= Void implies not parent = Current

and re-ran my content import program.

Bingo

Comments:
So simple, yet brutally effective! But why not simpler still:

valid_parent: parent /= current
 
Doh!

It's actually an interesting example of how one's mind can get stuck. I had just been looking at the feature which triggered the stack overflow:

is_relevant: BOOLEAN is do
Result := relevance
if parent /= Void
Result := Result and parent.is_relevant
end
end

Somehow that branching logic stuck in my mind as I wrote the invariant.
 
It's interesting to compare this with how Test-Driven Development might have tackled the problem:

1. Write a unit test that demonstrates the bug.
2. Run the test to prove it really does demonstrate the bug.
3. Fix the bug.
4. Run the test again to prove it's fixed.

The trouble with arriving at the test-driven fix in such a situation is that you do not know where the code is that is setting 'parent' invalidly; so you do not know which broken feature to exercise in the test.

Most likely, a test would be written to expose the symptom. Build an object whose 'parent' is itself; then call the routine that exhibits the stack overflow. The fix would probably entail adding a check to this symptom routine: if parent = Current then set_error_condition else continue_normally end. This would then require adding checks elsewhere, to see if the error condition had been set. And it would have fixed only this symptom, leaving other possible gremlins.

The DbC fix is simple, complete and easy. It's situations like this that leaves me convinced that TDD is a poor (albeit complementary) cousin to DbC.
 
I am working on a TDD Eiffel project... perhaps I should add an article here with my experiences
 
Post a Comment



<< Home

This page is powered by Blogger. Isn't yours?