Code Tips That Will Save Your Life #2 – Part I

5 באפריל 2012

no comments

Tip #2: Proper Exception Handling in .Net and in General.

I like to dissect programmers. Did you know I'm utterly insane?

Always code as if the person who ends up maintaining your code is a violent psychopath who knows where you live.

You can never know when this phrase will turn into horrible reality, so you’d better be prepared!


Tip #2: Proper Exception Handling – Part 1

This time on “Code Tips That Will Save Your Life” – Exceptions.
We all know them and sadly we all have to deal with them, but are you doing it right?

To most it seems like a very straightforward thing – Try, Catch maybe Finally, that’s it.  But code with incorrectly written Exception handling can be frustrating to maintain and hard to debug on a good day, but downright dangerous on a bad one. 
  
On this two part post I will share 8 Tips that will make your code amazingly easier to maintain, not to mention log and debug, and might even make it more stable.


1. Getting Up to Scratch

As I already said on a previous post about Application Stability:
Most Software Developers Are Lazy

I still stand behind this phrase, which is the only reason I’m not skipping this tip. So lets just make sure we are all on the same page here.

Think about a piece of code you wrote lately, an algorithm, a method or a class.
Now look at this snippet:

try

       // Do amazing things
}
catch

       // Things didn't go as planned, time for plan B
}
finally
{
       // Release resources and other awesome stuff
}

Does your code follow this pattern? 
If your answer was yes, than kudos, +2 Points.
If your answer was no.. well you better have a good reason for it.

There are very few cases in which you would not want to catch rising exceptions.
Even if you don’t really have anything to do with the exception at that place in the application flow, it’s usually good practice to catch it for logging purposes, resource management and for enriching it with information about the cause of the exception.

Obviously as with any rule, there are exceptions (pun not intended).
If there really is nothing to log, and no information to add, there is no reason to catch an exception for the sole purpose of throwing it again. But make sure that is the case.

What ever you do, the most important rule for you to remember is:
Never, ever swallow Exceptions without doing anything!

Bubble them, write to log, do anything.
But make sure your catch clause is not empty, or someday, some poor sap that will need to maintain your code will have a very, very bad day.

2. Being Specific With Exceptions

Let’s put exceptions aside for a second.

Imagine yourself at the office. You are working on that very very important project your boss expected you to finish yesterday.

When suddenly your IDE crashes, leaving you with the following message:

More or less, you have nothing to grab on to. You have no idea what went wrong. More important, you have no idea how to recover all your lost work.
You are left with nothing to do but contemplate your unplanned sudden career change.

Now with that in mind, imagine yourself using or maintaining someone else's code, or maybe even code you wrote a long time ago.
Then while Debugging it you get this:

The exception’s type is System.Exception, the exception message is “An error occurred”. No inner-exception, no relevant stack-trace.

What now?
If you are lucky you have the source code or PDB files, so you can spend anything between 15 minutes to several days debugging for an answer.
If you are unlucky, and you don’t have a way to debug that code.. well good luck guessing the reason.

When writing exception handling you should always have this example in mind. You need to make sure the exceptions your code throws can be easily understood, and this is done by being specific.

Being specific means two things:

1. Always make sure the exception message is clear. 
If you can predict the reason for an exception in the code, make sure the exception you throw includes that information, and even a suggestion on how to fix it.
For example: If a specific parameter you received for a method is null, make sure you specify the exact parameter that was sent as null, don’t just throw a “Null reference exception”.

2. Use the correct type of exceptions, and use custom exceptions if needed.
Exceptions come in many flavors:
NullRefrenceException, InvalidOperationException, IOException.. and the list goes on.
Usually you will find one that is relevant for you, or at least one you can derive from. But please use the basic
System.Exception only as a last resort.


On the flip side, you should also separate different exception types when catching exceptions, using several catch clauses. Separating exceptions by type will enable you handle different exceptions differently and log them appropriately.

For example:

try
{
    RunLogicOfGreatImportance(argument);
}
catch (TimeoutException timeoutExcpetion)
{
    // Action timed out, perform retry policy
}
catch (ArgumentException argException)
{
   // Argument sent was invalid, prompt the argument creator
}
/* etc. */
catch (Exception ex)
{
    // Something else that I didn't expect went wrong, log and handle
}

 

As you can see it’s always important to finally catch System.Exception. This is in case an exception of a type you didn’t expect was thrown.

P.S: I heard some people talk about performance implications of using multiple catch blocks. That’s simply wrong and in no way an excuse to skip this good practice. For more information check out this Benchmark on try/catch Performance.  


3. Custom Exceptions

O.K so here is the deal.
Sometimes the exceptions that are part of the .Net framework are not specific enough, or not relevant to the type of exceptions you need to throw from your code.

This is where the concept of Custom Exceptions comes into play.
Basically what it means is that you create your own Exception types by deriving from the exception types that are already in the framework.

The simplest way of doing this is using the exception snippet.
Simply click CTRL + Space and start writing the word “Exception”
 

Costume Exception Snippet for C# on Visual Studio

Select Exception from the list and press TAB twice.
What you will get is this lovely snippet of code:

[Serializable]
public class MyException : Exception
{
    public MyException() { }
    public MyException(string message) : base(message) { }
    public MyException(string message, Exception inner) : base(message, inner) { }
    protected MyException(
      System.Runtime.Serialization.SerializationInfo info,
      System.Runtime.Serialization.StreamingContext context)
        : base(info, context) { }
}

The snippet basicaly lets you select the type name prefix (leaving the word “Exception” at the end as a standard) and the Exception type it derives from (System.Exception the being default).

Now you can add whatever you want to this class.
Usually it’s good practice to add properties with more information about the exception reason, and maybe a GUID or some other type of ID for a log record regarding the exception.

To the question of “What exception type should I derive from?” there are two possible approaches:

Approach #1: Derive from the exception type that most closely matches the one you wish to create. Basically what this means is taking existing framework exceptions and making them more specific.

For example, you are writing a piece of code which needs to read a given configuration file and load it. In case the given file does not exist you want to raise an exception more specific than FileNotFoundException, so you derive from it and create your own exception type :  ConfigFileNotFoundException.

The advantage here is that even if the person using your code doesn’t know that it throws your custom exception, he will still catch it if handling the derived types.


Approach #2: Make one main exception type for your system/application or for the current application module (for larger projects) and have it derive from System.Exception (Not from ApplicationException!).
Now have every new Custom Exception you create derive from that type.

The advantage here, is that unlike the previous approach you have all your custom exceptions deriving from one application wide custom exception type, and you can even manage them all under the same namespace.

It’s a matter of preference, I personally prefer the second approach. When working on large projects especially ones involving several developers it’s a good standard to maintain among each other. It’s also generally a good method to separate internally, exceptions that were risen by the CLR from ones that where risen by the application code. This is good both for maintenance and logging.

4. Correctly Bubbling Exceptions

Here is a little test.
Read the following 4 lines of code performing exception bubbling, that  you would usually find inside a catch block, and see if you can spot the differences (for the sake of this test “ex” is the exception instance caught):

  1. throw;
  2. throw ex;
  3. throw new MyCustomException("Exception Message");
  4. throw new MyCustomException("Exception Message", ex);

So obviously syntax-vise they are all different from each other, but what actually is the difference in what happens when they excute?

If your explanation included “Inner Exception” that’s +1 Point.
If your explanation included “Call Stack” or “Stack-Trace” that’s +3 Points.
And if you have no idea, well there is nothing to be ashamed of, but stay tuned.

These fine differences are the kind of things that even seasoned .Net developers are just not familiar with. There is little to no documentation about this, especially on MSDN, where you’d think it should be under Exception Handling Fundamentals

So let’s go over each one and understand what it does and when we would like to use it.

1. throw;

What it does: Re-Throwing the just caught exception, Preserving the Call Stack leading to the exception being caught.

When will I use it: When you wish to catch the exception only to log it or do some kind or rollback logic, but bubble the original exception with the full Stack-Trace.

2. throw ex;

What it does: Same as the last one, only this time Not Preserving the Call Stack, actually cleaning it and starting it from the current place in the code.

When will I use it: Possibly never. The only good reason I see to do this is if you want to actually hide the Call Trace leading to the exception from the person using your code.
This could be because you already logged the full trace and don’t want to have it written again to the log. Another reason is that you provide a third party DLL and don’t want the exception to reveal all your calling trace. On both cases I find the next example a better option.

 

3. throw new MyCustomException("Exception Message"); 

What it does: Creates a new exception instance, with your own exception message. In the process tossing away the call stack gathered up to this point and creating a new one. Therefore Not Preserving the Call Stack.

When will I use it: On same instances described on the previous example. Only this time you have the added benefit of having the newly thrown exception be the one you created with your own exception message.


4. throw new MyCustomException("Exception Message", ex);

What it does: Creates a new exception instance same as the last time, but this time using the caught exception as the Inner Exception.
What it means is that all the information gathered in the exception that was caught is maintained inside the newly created exception, and in the process Preserving the Call Stack.

When will I use it: Probably this is the most useful one of the lot. It gives you both the ability to maintain the gathered trace, but also add to it your own information, and if you wish, have the new exception take the form of your own custom exception type.

In any case, you should not catch an exception just so you can re-throw it, unless you have a good reason.
Among these good reasons are: Enriching or Editing the exception details, Logging, Performing rollback and resource cleanup logic and so on.


That’s it for Part I.
Part II of this post will cover: Resource Management, Multithreading, Documentation and Design Decisions regarding Exceptions.
So stay tuned.

I Hope this post helped you.
If you have any comments, questions and other relevant or irrelevant things to say, please leave a message on the comment section bellow.

Josef.

 

Previously on “Code Tips That Will Save Your Life” :
Tip #1- Code Documentation

Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*