I’ve been reading Steve McConnell’s excellent Code Complete 2nd Edition, and it’s caused me to have an epiphany of sorts regarding dealing with errors. The funny thing is that I don’t even think that this section is particularly well written, nor do I agree with some of his conclusions. But reading it did get me to thinking about the way I code and the reasons I make the decisions that I do.
(Ok, Ok, so this book has been on my “Currently Reading” list for almost a year. Sue me. I got distracted with some other things.)
McConnell makes the following statement (emphasis his):
Use error handling code for conditions you expect to occur, use assertions for conditions that should never occur.
And then he goes on to detail how some best practices for error handling, when exactly you might use assertions, etc.
So here’s where we get into a little personal bias of mine. And reading this section caused a little introspection on the topic. I hate assertions in production code. I’ve read different versions of the above statement a thousand times or more, and still I’ve never found a good reason to use one.
McConnell actually brings up a couple better ones; one example he brings up is an X-ray machine. If the software for an X-ray machine encounters data it doesn’t know what to do with, it’s probably better off aborting than continuing in any fashion. You don’t want to give misleading information back to the doctor that could result in an incorrect diagnosis.
Surprisingly, at least to me, I thought of another. Ever since I wrote my first parser in college, I’ve been fascinated by compilers. I’ve gobbled up countless books on them, and tried out dozens of different ones. Unfortunately, my career path has taken me away from them, and other than some fancy expression evaluators, I’ve never gotten even close to writing a compiler. However, I can see wanting to use an assert in a compiler, as well. If you’ve scanned the tokens and you’re now parsing them, and you get a number token that contains “foo”, it’s probably time to abort. Either the lexical analyzer is broken, or your data has become corrupted somehow. Either way, you don’t really have any way of continuing (how can you trust any data that follows), so you might as well abort.
Ok, so I can see these cases. Maybe. (More to follow on the “maybe” later).
However, I’ve always written consumer or business applications with nice fancy graphical user interfaces. I think that leads to my bias against asserts. Quite a bit of my work has been in the component area for these projects, rather than the UI, which has an even stronger case not to use them. It’s not up to the component to decide to abort the application, it should just abort its processing and let the application decide what to do. An example would be a spell-check component for a word processor. If the spell-check component encounters surprising data (remember, we’re talking about the “this should never occur” type of data), you want the spell-checker to abort and the UI to give you a nice message box saying that the spell-checking has been terminated. You don’t want to get a message box saying that the application has encountered a problem and needs to close.
Now, the third way of dealing with bad data that’s available in most languages today is to throw an exception. McConnell doesn’t seem to think much of exceptions (surely they belong somewhere in that sentence about assertions and error handling above), and doesn’t even list them in his section on error-handling techniques. Most of the section on exceptions seems to be almost disparaging in nature, and centers more on how they shouldn’t be used rather than how they should. The first sentence in his concluding paragraph seems to sum up McConnell’s viewpoint perfectly:
Finally, consider whether your program really needs to handle exceptions, period.
With all due respect to Mr. McConnell, who is obviously a brilliant person, I think he’s totally missed the boat here and seems to have as much of a blindspot regarding exceptions as I do regarding assertions. In fact, they’re not all that much different. He grazes up against the truth in one particularly insightful sentence:
Exceptions are used in similar circumstances to assertions—for events that are not just infrequent but for events that should never occur.
Bingo!
Now let’s go back and look at that X-ray software. While an assertion might still be correct in some places, I still think the final decision of rebooting the software/hardware should be left to the user, not the application. It seems better to me to throw some sort of useful exception back to the UI, and let the UI deal with it rather than abort the application. Then the UI can ask the user if s/he wants to re-try the operation, or restart the application or whatever else seems appropriate.
Similarly, I think I’d prefer to use an exception in the compiler, as well. Although I still might abort processing when it occurs. I can much more easily provide the useful and necessary debugging information in an exception class than I can in an assert string.
Now, while I admit that proper use of exceptions can be a tricky concept, all of McConnell’s issues with them can be addressed in a style guideline document, which should be part of any large project anyway.
The end result of my introspection? I’ve decided that maybe I’ve been a bit wrong to be so harshly against assertions, and maybe too quick to use exceptions as traditional error handlers. But, I still prefer exceptions over assertions, and I don’t think I’m likely to change my mind any time soon. I’d rewrite the sentence from above as this:
Use error handling code for conditions you expect to occur, use exceptions for conditions that should never occur.
As a caveat to this rule, it may still be best for a component library to throw an exception back to the caller in some cases. They’re often more useful than an error code, and the typical error handling approaches (boundary values, last good value) may not apply at the component level anyway. Then the application using the component can decide if the exception is really something exceptional, or if it’s just an error that should be handled.
Perhaps I’ll spend some time adding detail to this and send it to Steve McConnell as a replacement for his section on error handling. ;-)
Now playing: Dolly Parton/Teresa Merritt/Whorehouse Girls And Customers - A Lil' Ole Bitty Pissant Country Place