I was coding some stuff this last Friday, trying to clarify to myself some of the feedback we've been getting for CAB, the Dependency Injection work we've done there and we are doing in EntLib, partial specifications, and related topics. I was playing on a prototype, which inclines me strongly to write unit tests carefully and with rigor. I do this because a good set of tests will make you think hard of the semantic requirements, scopes of collaboration, and other important issues of your program. I find it that choosing carefully which test to write next is orders of magnitude more significant than making code that will pass it. With good unit tests I consider this second step almost a trivial, inductive activity. It must be weird, if you're not used to seeing TDD, to watch me staring at empty space for a while, then after 10 minutes saying "aha!" and writing a 10 liner unit test... that fails.. and then writing 3 lines to make it pass. I guess that's my quirky way of being in the zone when I am by myself (pairing around spikes and prototypes is an order of magnitude better.. I cringe when I think the hours people -including me- spend coding on their own at weird times of day, when Mon-Fri 8-5 they congregate in buildings to do...email. But I digress.)

At one point during the day there was a couple of hours when my rigor kind of went down. That is something that pairing will prevent, but I didn't have anyone to turn to (not in the war room). I reverted inch by inch to the 'old way', making some notes on paper, hacking a bunch of classes 'that you just know what they have to do' with that high-speed caffeine/sugar/videogame high feeling..that you know will you pay for later. But I was typing typing typing typing pretending all was OK and exhilarated at the apparent speed. At one point in time I wrote a quick test (failed) and changed the code to make it pass and..failed. duh! I know what the issue is..went fix the code - remove-this-here, change-this-to-here, delete-this and run test and ....fails. Huh?. I looked again, and I had changed a different class than the intended one. My change made sense anyways, it was an improvement of the semantics (not just a refactoring) but then it hit me:

I changed a different class than I intended. The tests around that class still passed.

I panicked. Not only I had coded a new subsystem with appalling test coverage, but I had left a trail of vestigial cruft out of half-thought though requirements, interfaces with just one implementation, and the one trivial unit test that was NOT breaking was waving all my bad practices in my face. So I immediately reverted to the point where I hadn't made that change and try to analyze what test would have broken by that change. Finding the test that would have failed because of my change actually was easy, but once I coded it, it was clearly not good: it was an horrible statement of intent, a disgust of a specification, a shame of OOP, an insult to Liskov, a mooning to Demeter, and all those things that make your code brittle and plain evil. I did not want my code passing that test at all!

So I decided to stop and revert and analyze what had gotten me here. As a matter of fact making the ugly test meaningless (and thinking of the meaningful test) sent me on a quest though my code to revert, delete, and clean. Which made me happy since deleting code is my favorite programming activity. It was amazing how much semantic trash had crept in through a couple of missing and bad tests. (Of course if the architecture you are working in favors good modularization and separation of concerns it helps act as a 'containment wall' against such ugliness...but I was working at the core of a very generic component without these benefits. And, to reinforce, paring would have been even better). All that infectious spreading darkness, through one little fixture done wrong. The semantic spaces that we represent in code - especially OO code - are twisty and rich, and through one apparently small mis-understanding (by error, or in my case, by omission) can cause large, unpredictable and almost emergent side-effects elsewhere.

Which reminded me of the 18th? 17th? century discussions of space and spirit- how many angels can dance on the head of a pin? The question is strange because it seems to discuss dimensions totally orthogonal to each other - matter and spiritual force, exagerated by the use of a trivial pin and respect-inducing angels. So how much meaningful insights can leak through one bad or one missing unit test? I guess... just as many.

 

...godspeed to the sts-114 Discovery astronauts.