Monday, September 05, 2005

Little things add up

Being in the country, surrounded by fields and trees, my perennial garden requires constant weeding. A few nights ago I was out in the garden digging out some tenacious crab grass. At first I noticed pinprick or two on my arm and my legs itching. I ignored those slights and kept working. But after being bitten several times and feeling a persistent roving itching sensation around my ankles I stopped to investigate. A small army of teeny ants were streaming over my shoes, crawling up my pants legs, into my socks, over my gloves onto my bare arms… I ditched my shoes, socks, pants…and dashed inside. That ended weeding for the day.

I’m like that. I ignore little annoyances. Bug bites or a few scratches don’t stop me from weeding. I block out most distractions when intent on a task. It’s only when irritations exceed some threshold that I turn my attention to what’s bugging me. Otherwise small distractions, if I notice them at all, are easily brushed aside.

Software developers often have an unrelenting focus when tackling big meaty design problems. Little annoyances get brushed aside in the rush of making the design work. Who cares about those little bugaboos when exciting stuff is unfolding right before your eyes? And yet, those little things add up.

Why is it that we wait until there’s a persistent itch before we scratch it? I suppose it is human nature. If you let every little thing distract you, you’d never get anything done But design bugs don’t have six legs and initiative so they tend to hang around. If you don’t knock ‘em down and clean them up things can get really ugly. The more of them you have, the more difficult it is to get your design working. Yet when you’ve invested so much in your design you have to keep working at it (even if it would be better to scrap it and start afresh).

That why test-driven development is a big win. Writing tests first forces you to focus you on thinking about the interface before you design and code it. Making those tests work becomes a relentless way of getting observable behavior to work rather than letting crufty untested code pile up. But it isn’t enough. Writing a test is isn’t the same as testing for the quality of a design choice. Maybe that little design choice you just made should bug you (but it doesn’t) because you can’t tell whether it is just OK or what might make it better. If you are in this situation I have one bit of advice on how not to insert a little thing into your design that may end up biting you in the end:

If you find yourself writing code that asks an object whether it is in a certain state or whether it is capable of handling a request, and then turns around and asks it to do the right thing (based on its answer), think twice. This should bug you. There’s usually a better design choice that places the decision-making responsibilities inside the object that is being directed. A small example from my design course’s problem can illustrate. The problem is to create a design that sets the report interval for any kind of sensing device. Some sensing devices are “intelligent” and can be programmed to report at specific time intervals. Others have to be polled on a schedule. How should you design a controller that handles either case? A straightforward design might have a controller ask:

If sensingDevice.isProgrammable() then sensingDevice.setReportInterval(timeInterval)
else { /* code to add the sensing device to the poller at the timeInterval *}

My choice, instead, would be to would have the control code turn around and ask any device to set its report interval (and have the device make the decision based on whether it was programmable or not) to do the work. One line of control code with decision-making being done in the sensing devices:

sensingDevice.setReportInterval(timeInterval);

Instead of making explicit control decisions I always prefer delegating those responsibilities to objects that do things based on what type of thing they are. It makes for simpler control code and localized (encapsulated decisions). Objects that behave differently based on who they are and what capabilities they have can greatly simplify control code. Making objects smart can eliminate external decision-making.

I’m going to continue compiling a list of my favorite garden-variety design bugs and will be writing about more of them. If you have some seemingly innocuous design choices that bug you, I’d like to hear from you.