Home > C#, programming, software development > Tools of the Effective Developer: Error Handling Infrastructure

Tools of the Effective Developer: Error Handling Infrastructure

I often come across code with little or no infrastructure for error handling. This is a big mistake, one that’ll make you pay increasingly as the code base grows. Why? Because your code’ll end up with loads of this:

try
{
  ParseText(SomeText);
}
catch (Exception e)
{
  MessageBox.Show("Error while parsing.", "My Application",
         MessageBoxButtons.OK, MessageBoxIcon.Error);

  // Skipping the rest due to the error
  return;
}

It may look OK but there are several problems with the error handling code above, some more severe than others.

  • Code duplication
    A message box for displaying error messages to the user should almost always have an error icon, the application name as the title, and an OK button. Repeating this all over the code base is not very DRY and should be avoided.
  • Inconsistency
    A related problem is that when you leave programmers with only the general error handling routines of the platform chances are they’ll end up doing things differently, resulting in an inconsistent user experience; For example showing some error dialogs with an error icon and some without.
  • Information loss
    A more serious problem is the fact that the code in the example, by ignoring the exception object, drops information that could be important to track down a bug. We could of course mititgate that problem somewhat by showing the error message of the exception to the user (by concatinating e.Message), but we’d still miss an important piece of information: the stack trace.
    Since dumping a pile of function calls in the face of the users is a no no, what we’d really need is a way to put the details in a non-intrusive place, for example a log file. If the Error Handling Infrastructure doesn’t make this easy, we’re likely to leave that kind of information out completely. For shame.
  • Not automation-friendly
    But the most severe problem with a spread out usage of UI displaying methods like MessageBox is that it makes your code impossible to automate. If someone has to monitor a scheduled run of for example unit tests, and every now and then klick an OK button, it kind of beats the purpose of automation.

So here’s my advice: Implement a strategy for handling errors at the earliest possible time. That is, right after setting up continuous integration for the Hello world application.

Properties of an Error Handling Infrastructure

So how should a error handling infrastructure be like? There’s only one rule. It has to be easy!
If it isn’t simple to use, it won’t be used, and programmers end up using the general purpose message showing methods again, or worse, not doing any error handling at all.

I usually build my error handling interfaces around two use cases.

  1. Displaying error messages
  2. Logging error messages

These are often used in combination, for example

try
{
  ParseText(SomeText);
}
catch (Exception e)
{
  ApplicationEnvironment.ShowErrorMessage("Error while parsing: " + e.Message);
  ApplicationEnvironment.LogError(e);
  return;
}

Or, to avoid code duplication, combined into a single convenient method.

try
{
  ParseText(SomeText);
}
catch (Exception e)
{
  ApplicationEnvironment.HandleException("Error while parsing", e);
  return;
}

When you design your error handling interfaces don’t be afraid to add lots of convenient methods. Remember, it has to be easy to use and that’s what convenient methods are all about, as opposed to utility methods who generally need to be given more arguments. In this case I prefer the Humane interface design style instead of a minimal interface approach.

Needs to be configurable

Furthermore, the Error Handling Infrastructure needs to be configurable or support some other kind of dependency breaking technique like dependency injection. For instance, you should be able to mute all error messages intended for the user, and instead write them to the error log. This way your code will be able to run in a scripted environment, like during unit testing.

There are many ways to design an Error Handling Infrastructure. You could create your own message dialogs allowing the user to send a report right away, you could use the built in application log of the operating system or just plain text files, etc etc.

Whatever you choose to do, don’t forget to do it early and make it easy.

Cheers!

Previous posts in the Tools of The Effective Developer series:

  1. Tools of The Effective Developer: Personal Logs
  2. Tools of The Effective Developer: Personal Planning
  3. Tools of The Effective Developer: Programming By Intention
  4. Tools of The Effective Developer: Customer View
  5. Tools of The Effective Developer: Fail Fast!
  6. Tools of The Effective Developer: Make It Work – First!
  7. Tools of The Effective Developer: Whetstones
  8. Tools of The Effective Developer: Rule of Three
  9. Tools of The Effective Developer: Touch Typing
Be Sociable, Share!
  1. September 9th, 2009 at 18:16 | #1

    It’s funny that the one bit of functionality that you can guarantee every program must have — handling errors — is the one that some many programmer leave as an after-thought. Once when I was really young, I even skipped all error handling as a deranged form of optimization (I choice I regretted years later, when I ended up having to debug a port of the code).

    My philosophy for Object Oriented: handle it “low” or handle it “high”, but nothing in the middle. That is, either catch the error right away and do something useful with it, or allow it to propagate up to one big general error handler and have it dealt with there. Also, don’t throw an error if some other return value is also appropriate, e.g., return null or an empty list instead (and in-band signal like -1 is also appropriate).

    Paul.

  2. September 10th, 2009 at 10:05 | #2

    @Paul W. Homer
    “I even skipped all error handling as a deranged form of optimization”

    Ha ha! I thought the only reasons could be laziness or ignorance, but deliberately skipping error handling as an optimization, that was new to me. Classic! :-)

    “My philosophy for Object Oriented: handle it “low” or handle it “high”, but nothing in the middle.”

    For once I have to gently disagree with you. My philosophy is: Handle the error where it makes sence.
    This usually means handling it “low” or “high” (in fact more often high, in the GUI layer), but not always. It happens sometimes that I find situations where it makes sence to handle errors in the middle tire.

    “don’t throw an error if some other return value is also appropriate”

    The thing here is not to mute information about an error that could help identifing problems. A return value can only tell you OK, or NOT OK but nothing more. This is fine for really low level functions (like malloc) but should be avoided otherwise.

    But! If we’re not talking about an actual error, like for instance a search that resulted in no hits, then of course a return value is the correct way to handle it. Exceptions should not be used for anything other than exceptional (invalid) program states.

  1. September 7th, 2009 at 20:02 | #1