I think any developer with any amount of experience would agree that one thing you do not skip, rule-bend, or even do poorly is exception handling. I would add that it can be tough to justify complicating error handling by turning it into its own subsystem with a bevy of objects and possibilities.

 

For what it’s worth (I guess I could stamp that across every blog entry) here are my bare-minimum-yet-good-enough-for-most-common-business-application-development exception handling rules:  Do it, Be consistent, Keep it simple, Throw in the kitchen sink, Roll your own, Always at initial point of action, Only handle specific exceptions.

 

Do it

Like I said before, this is nonnegotiable, you use exception handling.

Be consistent

Be consistent across the solution. Everyone working on the project knows the simple rules and follows them in the same way.

Keep it simple

The simpler it is the more likely everyone will do it and be consistent. Make people justify any specialized exceptions.

Throw in the kitchen sink

Throw exceptions with every bit of data that could possibly be available to help the coder determine what happened.

Roll your own

Don’t call Parse on a type and let the code throw a “wrong format” exception, rather call TryParse and then throw in the kitchen sink when it does not work.

Always at initial point of action

Catch and deal with exceptions at the initial point in the application where the system is sprung into action. In the common business application, this is often behind a button click or some other event handler for a user control. In other words, when a process (no matter how small) kicks off, wrap the call in a try-catch block and deal with the fact that an unknown exception happened. The only code in an event handler for a control should be a try-catch block with a call to the action’s code.  If the exception has bubbled all the way back up to the event handler then something completely unexpected has happened. There's generally nothing to do now but apologize to the user and email the development team.

   private void btnAddFileToRelease_Click(object sender, EventArgs e)

   {

     try

     {

        TryAddingFileToRelease();

     }

     catch (Exception ex)

     {

       HandleExcpetion(ex);

     }

   }

     Only Handle Specific Exceptions

By handle I mean write code to deal with the fact that something specific has happened and the code can do something about it. In the above case (the initial point of action) the code catches a base exception because at this point there is nothing the code can do but tell the user the activity they tried did not work. If we know a specific exception could be thrown and the code can deal with that specific exception, it is important to deal only with the specific exception. For example, if a 3rd party's collection object throws an error when retrieving an item for a key and you want the code to handle that exception by returning null to the caller, you need to handle the specific exception; probably something like IndexOutOfRange. The mistake would be writing handling code for the base exception. If the collection threw a different exception (which truly means we should stop the whole show)...you'd never know about it

 

Notes

Unlike the old days, most modern programming environments provide a full call stack in an exception, so we know exactly where the routine bombed. Because of this we often don’t need exception handling all over the place. We need it at the initial point of action so our application stops gracefully and we need it when objects must be disposed.

 

Creating custom exceptions: Some coders seem to do this for every new exception they think of, often inheriting some base exception. This is poor OO programming to begin with even though it might look cool. A generic exception with a message that explains the unique error will suffice in 99% of the cases. Like many things I vote to keep exception handling simple before it turns into a subsystem all to itself that the "next guy" has to comprehend and maintain. Create a special type of exception if the code will behave differently because of the type. For example, if an exception is a network down exception, then the code might try again  n  number of times.

 

Simple Exceptions: Often code “knows” the context of a call and thus might know that a user could fix the issue. In this case a special Simple Exception could be thrown. When the exception reaches the client interface the exception could be handled differently. Instead of logging the error and emailing support, a simple message could be displayed to the user allowing them to fix the issue before trying something again.

For example, a system may allow users to define Widget Types and import Widgets into the system. During an import a Widget Type Key is read and the system looks up the Widget Type using they key. The code that does this could throw a Simple Exception if the Widget Type is not found.  The user would then get the message, set up the new type, and try the import again.

Just make sure your assumptions about whether or not the issue is user-addressable are valid. Often these assumptions that lead to Simple Exceptions being thrown are high on the call stack and not deep in the bowels of the system. Furthermore, Simple Exceptions are useful when you do not want to provide a list of issues for the user to address. Simple Exceptions also simplify process code since the number of conditional statements is greatly reduced. Instead of if x=true then [add issue], else continue we just have ThrowSimpleExceptionIfTrue(x).