Exception handling done the right way

I love exceptions, but I get a distinct feeling many people don’t when I see some horrific examples of their use. Especially from people who gets forced into using them by javas wonderful checked exception feature without truly understanding the concept. Or by people so scared of them that they hardly dare catch it, like way too many of the C++ crowd. In these enlightened days, exceptions don’t cause the problems they used to cause, unless you are working with old C++ code which doesn’t use auto_ptr. If you are, abandon all hope and refactor hard.

I’m going to assume you’re writing C# here, but everything I say goes for Java as well. It’s even better there since Java has checked exceptions. But without further ado here’s my handy-dandy guide how to do it right!

Why bother

Because it’s a graceful way of handling exceptional circumstances. Anything that is not considered a normal result of your method that might happen is an exceptional circumstance. Return values are not for exceptional circumstances. I assume you like the .NET framework or Javas similar environment. They’re nice because of exceptions! To see the alternative, take a look at for instance straight up COM in C++. It’s clunky as hell. Without exceptions, the only way to check for any errors is to check return values. Whenever you do something you’ll invariably get the real return value as a pointer-to-a-pointer and the method itself returns a HRESULT which you need to check. But of course, you won’t, since they almost never fail and you will forget. And you can’t read the code like it’s supposed to be read since the return values will be in the parameter list instead of in the actual return.

To compound the problem further C# has an out and a ref specification to parameters. Which is almost in all cases used for this sort of stuff, and almost always totally evil in my book for the reasons stated above. You should never ever do this sort of stuff:

string DoStuff(out BusinessObject bo) {
    // Doing stuff
    // ...
    // Business plan bad, return error
    return ".COM boom failed";
}

The only way to find out what went wrong it to do string compared on the return value. Evil. Return value checking should be a thing of the past for non-exceptional circumstances.

How do I do it then?

Lets start by how to not do it. Here’s a typical example of doing it wrong

void DoStuff() 
{
	// stuff goes wrong
	throw new Exception("Shit is hitting fans");
}

NO! You don’t throw the Exception class, never ever. I wish they made it abstract. This circumvents the catch statements intended use, makes it impossible to tell what’s going wrong and makes babies cry. If you specify an Exception type to catch it will catch every exception. Whatever it was you’ll have to figure out yourself. It might have been shit hitting fans, but it might as well have been a null reference. Maybe it was a division by zero. Who knows?

If shit is hitting fans, you throw a very specific exception relating preferably to that case and no other case.

public class ShitHitFanException : Exception 
{
    public ShitHitFanException(string message) : base(message 
}

void DoStuff() 
{
	// Danger Will Robinson!
	throw new ShitHitFanException("Scotty can’t change laws of physics");
}

And you catch it by catching the exception you need to handle, permitting the stuff you’re incapable of handling to bubble up to the surface. Maybe even to a crash, if that’s your cup of tea.

try
{ 
    DoStuff();
}
catch (ShitHitFanException e) 
{
    // Alert Will Robinson of danger.
}

This leads to my next point. You need to use base classes for your exceptions if they have any sort of common ground. Just routinely declaring exceptions as being subclasses to Exception like a big happy community of equals is evil. You need to categorize your exceptions into types of exceptions. For instance, if you have some sort of method which handles files, you might be throwing FileNotFoundException, DirectoryAccessDeniedException and DiskFullException. These have common ground, and should be labeled as such by inheritance. You need a IOException base class. This makes your catching code able to intelligently decide if it wants to handle exceptions specifically or more sweeping without resorting to acts of evil like catching Exception.

More importantly it also enables you to do cool stuff like

void ShuffleImportantDocumentsFromTopDrawer(Document[] topDrawer) 
{
    try
    {
        foreach (var document in topDrawer) 
        {
            try
            {
                document.shuffle();
            }
            catch (FileNotFoundException e) 
            {
                // Dog probably ate it. Log a warning and continue
            }
        }
    }
    catch (IOException e) 
    {
        // We end up here for BOTH DiskFullException and 
        // DirectoryAccessDeniedException
        CallTheItGuy();
    }
}

This is impossible to do gracefully if you have screwed up your inheritance chain or are catching Exception itself. Exceptions have no relation to another, and you can’t catch two similar exceptions handling them the same way without resorting to copy and paste or putting the handling in a separate method, which is weird and ugly. This is oftentimes a problem wih Java file IO. They throw exceptions like there’s no tomorrow and you’re required to catch them all. You probably want to handle some of them the same way. Catch the base class and you’re set.

But, I don’t want to handle it you say. I want someone else to do it for me. First of the bat, lets never ever do this again:

try 
{
    FaultyMethod();
}
catch (FaultyException e)
{
   // Whoops. I cant handle this stuff. Do some clean up and signal errors again
   throw new OtherException("There was a problem with faulty method, big surprise");
}

NO. There’s one huge glaring problem here. You are marshalling away the cause of the exception! The hard and fast rule is: If you are throwing something from inside a catch, you need to supply the exception you throw with it’s underlying cause. Here is the corrected code:

   throw new OtherException("There was a problem with faulty method, big surprise", e);

See how we added the e to the constructor. This makes a world of difference! When you print a stack trace, you’ll be pointed to the correct line, instead of being pointed to the catch block which says absolutely squat about the real nature of the problem.

Another point I’d like to make is that you shouldn’t throw another exception unless you have changed the meaning. But you can still catch stuff and log. As an example, say you have a SOAP service. Since you are diligently applying the principles in this article, you’re using exceptions to handle SOAP errors (they serialize fine, don’t worry about it). But you want a log on the server side as well of any exceptions sent to the client. Enter the second (under)used use of the throw keyword – the parameterless throw.

string MySoapyMethod(string param) 
{
    try 
    {
        // Do cool stuff that fails...
        BrokenCode();
    }
    catch (BrokenException e)
    {
        // Log this stuff so that we know about it
        Log.Error("Broken stuff in Soapy method", e);
        throw;
    }
}

This will throw the exception without altering it in any way. This is the other legal way of handling stuff you don’t want to or can’t handle. A final point, when you log using your logging framework, such as log4net, you typically get an option to pass an exception. Use it. If you have an exception logging, never log Log.Error(e.Message). Always log Log.Error("A real description of what went wrong", e). That way, you’ll still preserve the precious stacktrace.

Advertisements
Tagged , ,

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: