Guidelines for consistent exception handling


Exception handling is an essential concept in object oriented programming. It permits us to indicate program or method failure in way that it does not affect the method signature and thus, not affecting the overall design of our methods and classes.

However, exception handling is maybe the most misunderstood part of OOP as far as I have seen. Some think that exceptions are an evil we must live with; an evil that oblige us to decorate our code with a ‘Try/catch’ block whenever we think that an exception may arose. I do think though that exceptions, when used appropriately, can be our ally in making our code more robust and error proof. Exception handling is also a major part of an application design and we should give it the necessary thinking time that it deserves.

In the following article, I hopefully try to put some light on good practices in throwing, catching and designing methods to deal with exceptions.

What is considered an execution failure?

Often, we wrongly consider that we should throw an exception only at exceptional circumstances. The rule actually is “If the method does not what its names suggests (aka what it is supposed to do), it should throw an exception to notify it” (1). A good example is the .NET framework : if you try to open a file for writing but the file is a readonly file, the method will throw an exception because it could not open the file as the method name suggests it. That is said, it is not an unhandled case in terms of the code of the Open method, but it is not a normal execution path neither.

Exception handling versus returning error codes

This is probably a wide topic but I am going to give the main reasons why we should not use error codes instead or even in conjunction with exceptions (by using an error code to identify the nature of the exception).

  • When using error code, we must usually find a way to also return whatever the method is supposed to return. That either makes us change the signature and use (out) parameters or (worse) embed the error code and the returned type into another class/structure.
  • Another reason, and probably most important one, is that whenever we call a method that returns an error code, we must test it otherwise, we may let the code execute in an unstable state and eventually, propagate the error to upper layers of the application. On the other hand, if we throw an exception, it should be either explicitly caught or the application will simply terminate. This makes the code more robust since even if we forget to catch an exception, we will notice it while testing which is not the case if we use error codes and forget to check returned codes.
  • An exception contains much more information than an error code. It contains the exact location of the encountered issue and it should contain, in the message, the exact reason of failure and, for well designed exceptions, how to fix the problem. We no longer need to document each error code and manage error codes duplications. The exception contains all the information developers need to know.
  • If we want an error to propagate to upper callers in the stack, we just let the exception unhandled and it will be propagated to upper layers. Whereas using codes, we must test for the code, return it and do this for all the callers of the method at all levels.
  • Exceptions can be instrumented and monitored using standard applications in Windows.
  • When debugging, we can set the debugger to start when a certain type of exception is thrown.

Sometimes we see developers returning an exception instead of an error code (return an exception type as the return parameter of a method and not throwing an exception) as in the following code.

     public InvalidPayDateException CalculatePayAmount(out double pay) {}

Actually, this type of error handling defeats most of exceptions’ benefits that we just have seen. Thus, it is better not to return exceptions instead of error codes. That is pretty much the same thing as returning a simple code.

 

Throwing exceptions

As mentioned before, an exception should be thrown whenever the method can not complete its execution normally even if the scenario could be predictable in some way. Opening a file that does not exist should raise an exception for example even though we probably are testing for the existence of the file before opening it. Throwing an exception is like saying ‘Everybody above! There is an issue here and I cannot continue to execute normally!’ and this message will go up until someone (code) knows what to do about it to stabilize the code and continue.

A good place to raise exceptions is in the method pre conditions. Pre conditions are a set of tests on the passed parameters (or execution context) to ensure that all parameters are valid and we can continue to execute the method.  If we look at the following code, chances are that the method is called with an employee object set to null which will cause an exception thrown by the CLR.

    public class PayManager
    {
        public double CalculatePayAmount(Employee employee)
        {
            double payAmount = 0;
            if (employee.PayMode == PayMode.BiWeekly &&
                employee.LastPaid > DateTime.Now.AddDays(-14))
                throw new InvalidPayDateException("This employee is not supposed to be paid this week");
        
            payAmount = 2000; // of course, not everyone is paid 2000$
            return payAmount;
        }
    }

Now the same method with pre-conditions will throw an exception with more details (customized details that could contain much more information for developers).

     public class PayManager
    {
        public double CalculatePayAmount(Employee employee)
        {
            if (employee == null)
                throw new ArgumentNullException("The employee object must never be null");
            double payAmount = 0;
            if (employee.PayMode == PayMode.BiWeekly &&
                employee.LastPaid > DateTime.Now.AddDays(-14))
                throw new InvalidPayDateException("This employee is not supposed to be paid this week");
           
            payAmount = 2000; // of course, not everyone is paid 2000$

            return payAmount;
        }
    }

Of course, this is only valid for things we can check before the method does what it should do. In the core of the method, we may need to throw exceptions as well and it is very important to pick up the right exception type to throw being it an existing type or a custom type we create for the purpose of the application.

Choosing the right type to throw

One way to choose the right type of exception to throw is to use the caller perspective. In other words, we need to answer the question  “what type of information should the caller know in order to be able to do something if it catches the exception?”.

For instance, a method can throw several custom exceptions to indicate different issues and, on the caller side, even though these exceptions will be caught separatly (each type has its own catch statement), the treatment will be exactly the same. In such scenario, we will end up with a lot of code duplication as shown in the following code.

        public void DoSomething()
        {
            try
            {
                callMethod();
            }
            catch(customOneException ex)
            {
                log(ex);
                RollBackTransaction();
            }
            catch(customTwoException ex)
            {
                log(ex);
                RollBackTransaction();
            }
            catch(customThreeException ex)
            {
                log(ex);
                RollBackTransaction();
            }
        }

If we have considered the caller in our ‘doThisThing()’ method design, we would have thrown only one type of exception instead of the three and the caller code would be cleaner. This is not always possible, however we should always keep in mind how the caller will catch and treat different exceptions we may throw.

Creating custom Exceptions

I like a definition I have read in the ‘Framework Design Guidelines’ book: “Do not create an exception type if it can not be handled differently from existing .NET framework exceptions’. That makes the focus on how the exception is caught and not only on the nature of the exception as we may tend to do usually. In other words, if there is no added value for the caller in having a new exception type, do not create one and use standard exception types instead.

There are many “generic” exception types that can be used in different scenarios:

  • ArgumentInvalidException, ArgumentNullException and ArgumentOutOfRangeException
  • InvalidOperationException

If we consider these exceptions, we figure out that they may cover many cases of invalid arguments or, for the latest, an operation that we attempt to execute on an object in an invalid state for instance.

There are other exceptions that we should avoid using such as those thrown by the CLR (OutOfMemoryException, StackOverflowException and alike). Only the CLR should be able to throw these types. Another particular case is the System.Exception: this exception should not be thrown because it does not tell anything about the encountered issue. Remember that the type of the exception is actually the first indication of what caused it and using one custom type for the whole application is as inefficient as using the System.Exception base class.

Performance considerations

We must be careful not to have very common scenarios that provoque too many exceptions which will impact the performance. In such case, we should use one of the following two patterns:

Tester-Doer Pattern

Let’s say we do have a pay calculator that calculates the pay amount for an employee. To make things a bit more complicated, let’s consider that we do have weekly and bi-weekly paid employees. The PayManager may throw an exception in the case we try to calculate a pay for an employee that is not supposed to be paid that day.

Now, if we look at the following code:

    public enum PayMode
    {
        Weekly,
        BiWeekly
    }

    public class Employee
    {
        public DateTime LastPaid
        {
            get;
            set;
        }

        public PayMode PayMode
        {
            get;
            set;
        }
    }
   
    public class InvalidPayDateException : Exception
    {
        public InvalidPayDateException() : base() { }
        public InvalidPayDateException(string message) : base(message) { }
    }

    public class PayManager
    {
        public double CalculatePayAmount(Employee employee)
        {
            double payAmount = 0;
            if (employee.PayMode == PayMode.BiWeekly &&
                employee.LastPaid > DateTime.Now.AddDays(-14))
                throw new InvalidPayDateException("This employee is not supposed to be paid this week");
           
            payAmount = 2000; // of course, not everyone is paid 2000$

            return payAmount;

        }       
       
        public void CalculateEmployeesPay(ICollection<Employee> employees)
        {
            foreach(var employee in employees)
            {
                try
                {
                    var pay = CalculatePayAmount(employee);
                    //do something with the pay.
                }
                catch(InvalidPayDateException)
                {
                    //Do something
                }
            }
        }
    }

The first thing we notice is that every two weeks, there will be a number of cases where the InvalidPayDateException will be thrown because many employees should only be paid on a bi-weekly basis. This may have an impact on the performance and since it is a predictable scenario, we certainly should do something to avoid it.

One solution would be adding a method ‘IsValidPayDay(Employee)’ which will indicate whether or not the current date is valid for the current employee. Then, we will modify the method CalculateEmployeesPay in order to first check whether the current date is valid for the current employee and only in this case, do a pay calculation.


    ...
    public class PayManager
    {
        public double CalculatePayAmount(Employee employee)
        {
            double payAmount = 0;
            if (!IsValidPayDate(employee))
                throw new InvalidPayDateException("This employee is not supposed to be paid this week");
           
            payAmount = 2000; // of course, not everyone is paid 2000$

            return payAmount;
        }

        public void CalculateEmployeesPay(ICollection<Employee> employees)
        {
            foreach(var employee in employees)
            {
                if (IsValidPayDate(employee))
                {
                    var pay = CalculatePayAmount(employee);
                    //do something with the pay.
                }               
            }
        }
      
        public bool IsValidPayDate(Employee employee)
        {
            if (employee.PayMode == PayMode.BiWeekly &&
                employee.LastPaid > DateTime.Now.AddDays(-14))
                  return false;

            return true;
        }

   }

In this case, using the tester-doer pattern is legitimate and in fact, it may save us a number of unnecessary exceptions. However, there might be cases where the tester will be too expensive in itself; for instance a tester that will have to grab information from the database. Eventually, such tester will cost more than throwing exceptions and one way to avoid both, too many exceptions and an expensive tester, we should use the Try-Parse pattern.

Try-Parse Pattern

The Try Parse pattern consists in exposing a method and an exception safe version of the same method so that other programmers will be able to call it without paying attention to the exception. In .NET framework such pattern is used for the DateTime.Parse method. In fact, there is another version of this method called DateTime.TryParse which returns a boolean indicating whether the method succeeded or not and an OUT parameter that contains the resulting DateTime object in case it is successfull.

Generally speaking, when we use this pattern, we should provide both methods: with and without exceptions and both methods have the same name with a “Try” prefix for the exception safe one.

In our example, if we use the Try-Parse pattern, we add a TryCalculatePayAmount (same name with the Try as prefix) and as a result we will have the following code:

    public class PayManager
    {
        public double CalculatePayAmount(Employee employee)
        {
            double payAmount = 0;
            if (employee.PayMode == PayMode.BiWeekly &&
                employee.LastPaid > DateTime.Now.AddDays(-14)))
                throw new InvalidPayDateException("This employee is not supposed to be paid this week");

            payAmount = 2000; // of course, not everyone is paid 2000$

            return payAmount;
        }

        public bool TryCalculatePayAmount(Employee employee, out double pay)
        {
            bool result = true;
            try
            {
                pay = CalculatePayAmount(employee);
            }
            catch (InvalidPayDateException)
            {
                result = false;
            }

            return result;
        }

        public void CalculateEmployeesPay(ICollection<Employee> employees)
        {
            foreach (var employee in employees)
            {
                    double pay = 0;
                    if (TryCalculatePayAmount(employee, out pay))
                    {
                        //do something with the pay.
                    }
            }
        }
    }

Catching exceptions

Now, let’s talk about the other side of the exceptions. The catching. There are three main points to consider:

  • When do we catch an exception
  • What exceptions’ types should we catch
  • What should we consider when rethrowing and wrapping exceptions.

When do we catch?

We catch an exception only when we do something about it. The something about it can be anything like:

  • Solving the problem so that the program can continue to run.
  • Wrap the exception in another exception type to add more details about the context and rethrow it.
  • Stabilize the program and rethrow the same exception
  • Log the exception and continue as if nothing happened.

That is said, we should always avoid a Try-Catch-Finalize block with an empty Catch section. This will only hide potential issues. However, having a catch section that just rethrows the same exception can only be useful if the finalize section does something otherwise, we better remove the try-catch block at all.

What do we catch?

We should never catch the System.Exception exception (too generic) neither should we catch CLR exceptions (StackOverflowException, OutofMemoryException etc…). For the first, the reason is that catching the exception base type does not give us any information about what really happened. It is ‘blind’ catching which will hide all other sorts of exceptions (including CLR ones). For the second, the reason is pretty obvious: we cannot do anything to solve a stack overflow problem for example. In very rare circumstances, we may need to catch an OutofMemoryException but in most scenarios, we should not do it and let the exception go up.

The most precise in our catch statement we are, the more robust is our code because it will show us, in testing, what are the potential issues (exception types) that may arise from a particular method. If we ‘swalow’ all the exceptions, despite their type, we may feel that the code is robust but in reality, we’re just hiding real potential issues.

Rethrowing and wrapping

  • When rethrowing the same exception, we better use ‘throw’ (without arguments) otherwise, we will loose stack information.
  • When wrapping an exception, it might be a good idea to include the original exception as the inner exception (to keep some information about the original context).
  • Consider wrapping exceptions to give more details about the context. For instance, a caching component (that does file caching) may have a FileNotFoundException thrown when it tries to access a cache file. However, for its users, that might not have enough information to understand the exception. In this case, we should wrap it in a CacheFileNotFoundException (custom type) that contains information on the query we have done to the caching component for instance.

Conclusion

Exception handling is an important part of any software programming and it is very important to take the time to think about an approach before starting a new project. In this article I tried to go through the most important aspects we should take into consideration without going in too much details in some cases. For this reason I added the references below of two excellent books that, among other things, cover exception handling and programming rules in general.

References

  • (1) Framework Design Guidelines Second Edition (Conventions, Idioms, and Patterns for Reusable .NET Libraries) – Addison Wesley -
  • Clean Code (A Handbook of Agile Software Craftsmanship) – Prentice HALL -
About these ads

15 thoughts on “Guidelines for consistent exception handling

  1. Pingback: Helltime for August 31 « I Built His Cage

  2. Thanks for writing this blog post: There is not enough thinking going on about the proper way to handle exceptions.

    I’ve experimented with several ways to handle errors in large projects, including throwing/catching exceptions and using error codes. I find that using exceptions within a library (“Tester-Doer”) is fine, but between libraries I like using out parameters. As a library designer, it is straightforward to put an out parameter in the interface to communicate that “something” needs to be checked, and then in a code review it is a fairly easy and obvious thing to catch if a developer has ignored an out parameter. Often, exceptions thrown in unfamiliar libraries aren’t likely to help a developer initially understand a non-trivial bug anyway – they will always have to open the offending library and step through it in the debugger – but enough information can be passed up the line to generate an error message for a logger or a user. I tend to think of libraries as “soap bubbles” and that within each soap bubble we use exceptions freely and between soap bubbles we use out parameters.

    As a once and future Java programmer, one thing that I initially missed in C# was checked exceptions, though they can be quite hellish to maintain in a large project. Out parameters are actually quite nice in that respect: they are a sort of cheap way for one developer to signal to another, “Hey, pay attention because this method should be checked for error conditions.” without dragging the compiler into the mix. There is an interesting conversation with Anders Heljsberg on checked exceptions at http://www.artima.com/intv/handcuffs.html. (Hmm… the URL didn’t give away his opinion did it?)

    FYI: I found this blog post despite its absence on the LinkedIn LINDUG .Net group. It appeared in my morning digest, but was removed by the time I tried to read it. I found this by following your LinkedIn profile to your blog. Why was it removed? It is a nice post.

    • hi Greg,

      Thanks for the long comment. I appreciate it.
      To quickly answer the question: I did not know that my post was removed. I will ask the moderators for the reason they removed it.

      Regarding the checked exceptions in Java, I tend to agree with Rob C Martin (Clean Code) in that we should not use them because it tight couple layers of your application and go against the Open Close principle (Rob’s book is very good). I think it goes the same direction as the article you mentioned.

      Regards,
      Samir Bellouti.

  3. Pingback: Guidelines for consistent exception handling

  4. Overall a very good and useful post. Two comments:

    1) I believe that failing to mention the Exception Handling capabilities of the Enterprise Library [by Microsoft's Patterns and Practices] is a significant oversight. This provides a extensible, configurable, documents, proven basis for so many aspects of a robust design/implementation

    2) (Slightly more subjective and not related to exceptions) I believe that your use of the “var” keyword is inappropriate (and unfortunately becoming far too common. var is strongly typed, and the compiler efectively replaces it with the actual type at compile time [i.e. is is NOT "dynamic"]. Thus the use of it is viable in two situations:

    2a) The exact type can not easily be inferred by looking at the code, and is immaterial to the actual functionallity. This may be a highly complex nested generic type which is returned from one library method, and must simply be passed to another library method [ie no local operations]. This is the “WhatEver” substitution principle.

    2b) The exact type is very likely to change during development [ie between compiles]. This is much less common when viewed for situations where 2a does NOT apply.

    Using “var” for the sole purpose of saving keystrokes (in this case a grand total of 5 keystrokes) compared to the lowered readability, and increased potential for significant but subtle defects is (almost) NEVER a viable reason.

    • Thanks for the comment.

      For what regards the EntLib, I did not mention it because I was trying to talk about Exceptions from the OOP standpoint. I am planning to write a second article regarding strategies for error handling and, for sure, I will cover EntLib.

      For the usage of VAR, I do not have an argument actually. Although I am not a fan of the ‘Var’ usage, I do use it a lot when prototyping and writing demo code (it goes faster since the code generally changes a lot). Maybe I should reconsider this when I write code to be published.

      Thank you.

  5. A very nice article. There was one thing that either I don’t quite understand or it was mis stated. In the section that describes the use of error codes vs. throwing an exception you wrote the following:

    Sometimes we see developers returning an exception instead of an error code. Actually, this type of error handling defeats most of exceptions’ benefits that we just have seen. Thus, it is better not to return exceptions instead of error codes.

    Doesn’t this statement disagree with the rest of the article? Unless I am missing something I thought that the paragraph would have said:

    Sometimes we see developers returning an error code instead of an exception. Actually, this type of error handling defeats most of exceptions’ benefits that we just have seen. Thus, it is better to return exceptions instead of error codes.

    Thanks

    • hi,

      I meant that developers will return an excetpion as the returning type of a method (returning is not the same as throwing an exception). For the sake of clarity, I changed the wording and added a line of code to illustrate it.

      Thanks a lot for point this out.

      Regards,

  6. @Samir, looking forward to your next article. The reasons I brought up both points are as follows:

    1) Exception Handling is difficult to get “right”. People are likely to read an introductory article, and think that the information is sufficient for use in production code. About 3 years ago my company was contracted to perform a security audit on a webservice suite. The client had wrapped all exceptions so that caller would only see one type of exception. This was the way be were able to get past all of their security: Since they wrapped (rather than replaced), we had all of the details of the inner exception including the stack traces which allowed us to reverse engineer much of their architecure simply by forcing the service to generate exceptions.

    2) Similar to the first, techniques in “demo/prototype” have a very bad habit of leaking into other areas. In this particulare case:

    public void CalculateEmployeesPay(ICollection employees)
    {
    foreach(var employee in employees)
    {
    }
    }

    A reader who assumes that the posted code follows best practices might be likely to use var when the exact type is known, stable, and simple. When this feature first became available, I even know of teams who did massive replacements of existing type declarations with “var”. It is very unfortunate that tools such as ReSharper make this a trivial act.

  7. Samir :hi,
    I meant that developers will return an excetpion as the returning type of a method (returning is not the same as throwing an exception). For the sake of clarity, I changed the wording and added a line of code to illustrate it.
    Thanks a lot for point this out.
    Regards,

    Thanks for clarifying this and thanks for the exceptional (pun intended) article.

  8. Might want to site J.Richter if you are going to use his words and even his example.

    “Often, we wrongly consider that we should throw an exception only at exceptional circumstances. The rule actually is “If the method does not what its names suggests (aka what it is supposed to do), it should throw an exception to notify it” (1). A good example is the .NET framework : if you try to open a file for writing but the file is a readonly file, the method will throw an exception because it could not open the file as the method name suggests it. That is said, it is not an unhandled case in terms of the code of the Open method, but it is not a normal execution path neither.”

    • Right mate. I did not want to copy/paste but I was definitely, and clearly I guess, inspired by J.Richter’s sentence you mentioned.

      Thanks for taking time to comment.

  9. Thanks Samir, for a very good article. But, I’m compelled to comment that I think you got the “Try-Parse” example backwards. The whole point of the “Try” method is to avoid throwing an exception. So it should implement the “real work” and return an error code. The “normal” method should check the error code and throw an exception if required.

  10. Hi Samir,

    Good article. The ‘Whither Error Code is needed when Exception can do the job’ debate is not new, Though it adds a layer of inconvenience for development, Error code is meant to be mapped to User friendly strings for the end user who would not want to see the error stack (unless he clicks on a more info link or visit the logs – for support and debugging issues). That has been the single most reason for success in atleast one enterprise app that I worked on, You’ll agree with me that it is refreshing to see something more friendly than ‘Error has occured – please contact your System administrator :)’.

    About Checked exception – From the Sun website: Here’s the bottom line guideline: If a client can reasonably be expected to recover from an exception, make it a checked exception. If a client cannot do anything to recover from the exception, make it an unchecked exception.
    But Alas, throwback; would be worse :).

  11. Pingback: Guidelines for consistent exception handling « Samir Bellouti exception

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