(Another post in my “What is ‘Good Code’?” series…)
What should you do when software doesn’t work the way you expect?
Surprising behavior. Photo credit: epicfail.com.
You have to have a plan. The plan could bring one (or several) of the following strategies to bear:
- Reject bad input as early as possible using preconditions.
- Get garbage in, put garbage out.
- Throw an exception and make it someone else’s problem.
- Return a meaningful error.
- Log the problem.
These choices are not equally good, IMO, and there are times when each is more or less appropriate. Perhaps I’ll blog about that in another post…
Regardless of which strategy or strategies you pick, the overriding rule is: develop, announce, and execute a specific plan for handling problems.
This rule applies at all levels of code — low-level algorithms, modules, applications, entire software ecosystems (see my post about how software is like biology). The plan can be (perhaps should be) different in different places. But just as the actions of dozens of squads or platoons might need to be coordinated to take a hill, the individual choices you make about micro problem-handling should contribute to a cohesive whole at the macro level.
Notice that I’ve talked about “problems,” not “exceptions” or “errors.” Problems certainly include exceptions or errors, but using either of those narrower terms tends to confine your thinking. Exceptions are a nifty mechanism, but they don’t propagate across process boundaries (at least, not without some careful planning). Sometimes a glut of warnings is a serious problem, even if no individual event rises to the level of an “error.”
Evaluate the plan(s) for problem-handling in one corner of your code. Is the plan explicit and understood by all users and maintainers? Is it implemented consistently? Is it tested? Pick one thing you can do to improve the plan.
No, I’m not going to talk about genetic algorithms. (Not yet, anyway.)
DNA ~ subroutines. Photo credit: dullhunk on Flickr.
Consider the scope of concerns (roughly maps onto need for expertise) of various folks that do biological science for a living. You have organic chemists. They might not know much about why zebra mussel infestation is a problem in the Great Lakes, but they can tell you all kinds of things about why cellular respiration works or how prions replicate. You have cellular biologists, who know all about protein transcription, meiosis, and telomeres. At higher levels of abstraction/generalization, you need experts on tissues, organs, or entire organisms — and beyond them, you need folks who study speciation, ecosystems, genetic drift in populations…
Same deal with computers. At the lowest level, there are hardware folks who are all about making the chip or the bus efficient. Then there are algorithm specialists who will hone a sort or a data structure till it hums. Their expertise is critical, but not sufficient. You also need folks who are good at building well-encapsulated classes (cell membrane ~ encapsulation; nucleus ~ private methods; abstract factories = ribosomes… interesting…), folks who understand libraries (tissues/organs), folks who can see how each library and class fits into a coherent application (organism). Many analyses of software stop at the application level, but you can keep going: distributed applications clump in “herds”; herds participate in even larger and more complex (eco)systems that suffer from predation, evolution, and all the rest.
Morals to the story?
- Just as not all great biological scientists are experts in protein transcription, not all great computer pros are experts at low-level algorithms and data structures.
- Biology has a lot to teach us about building stable systems. There’s a reason organisms develop defense mechanisms, excretory capabilities, etc. Apps that evolve without analogs will die. Next time you are solving a tricky computer problem, ask yourself how biology solves the equivalent…