Tuesday, November 20, 2007

Exception Handling 101

  1. In some older languages, the runtime was not able to expose a call stack when exceptions occurred. This led to programmers spattering the code with exception handling-code, so that they would have a better idea of where exceptions occurred.
  2. Historically, programmers have sometimes used exceptions to communicate status.

The above 2 ways of doing things are no longer appropriate.

First, in a language which exposes an exception call stack (like C# or VB.NET), the only place you need an exception handler is at the top-most point of a thread. So, you need a try...catch around your application entry point (Main sub), and around every new thread you manually spawn.

Second, using exceptions to communicate status is a terrible practice. I cannot articulate why really. Perhaps because it forces you to code everything very defensively, which obscures the intention of the code. In any case, experience shows that things are much simpler if you follow the rule that exceptions are only for exceptional scenarios. In other words, do everything you can to avoid having to trap exceptions.

This is harder than it sounds. It pairs well with the "fail fast" rule though. You can implement this rule by validating parameters to your methods. If they do not meet your expectations (e.g. something is NULL when it should not be), then throw an exception. The intention of the exception is always to indicate an invalid system state. (An invalid system state is unpredictable and dangerous, and should never occur - it is an exception).

3 comments:

Agile Jedi said...

Great insight...I too have finally come to accept that exceptions should not be used as a "messaging system". Basically, if an exception does happen then something went wrong...you shouldn't expect an exception. Throw it up to the top!

I do believe exception handling is important for logging. Exception logs are an important debugging tool. We use log4net...this allows us to adjust application wide logging levels from a single location.

----
readme @ http://dan-thinks.blogspot.com/

Paul W. Homer said...

If you go too far with excessive exception handling you are essentially burying another complete program into your original logic. So now you have several overlapping programs, which is ugly and hard to follow.

An approach I've always found to work really well is to treat errors like any other functionality in the system. Wherever possible if the error isn't important I wind it into the normal behavior. If it is something for the user, I make sure it is very clear and distinct (for help files and tutorials). If not, then it is bound for support so it should provide enough information that it can be screen printed and emailed for example.

Sometimes I put in 'usage' errors. These are to stop other programmers from misusing parts of the interface. When released, these are either turned off or directed quietly into a log file.

Error handling is the one function that all programs share in common. The best trick is to get in enough information that the computer does most of the diagnostic work for you. Nothing is better than it coming back and telling you that you mistyped something on line 12. Especially if its 4am in the morning.

Paul.

Melloware said...

I just had this argument on my current project. I am now a Java developer but used to be a Delphi developer where all exceptions were unchecked. It let the code be clean and you only caught exceptions usually at the topmost level. It let your code just be good code.

However in Java people have gotten crazy with checked exceptions. I end up having catch clauses everywhere or throws clauses when i really don't need them. So I designed my module to use a base exception class that is an unchecked exception so my code was clean and my interface signatures were clean. Well the pointy haired boss decided Checked exceptions would be better and so I had to change my code. Which in turn meant adding throws to all my signatures and try..catch's around everything to the point that now the code is definitely less readable and we actually gained nothing with the checked exceptions.

The Spring Framework is also a fan of unchecked exceptions and it allows for some really cool things with dependency injection. Like catching Hiberate errors in and determining what to do with them in your Spring config file rather than directly in the Java code.

Just my two cents...

p.s. I miss Delphi.