Wednesday, September 24, 2008

Exception handling - Patterns, Classification, Best Practices

Exception handling is a programming language construct or computer hardware mechanism designed to handle the occurrence of some condition that changes the normal flow of execution.

Exception safety

A piece of code is said to be exception-safe if run-time failures within the code will not produce ill effects, such as memory leaks, garbled stored data or invalid output. Exception-safe code must satisfy invariants placed on the code even if exceptions occur.

There are several levels of exception safety:
Failure transparency, also known as the no throw guarantee: Operations are guaranteed to succeed and satisfy all requirements even in presence of exceptional situations. If an exception occurs, it will not throw the exception further up. (Best level of exception safety)

Commit or rollback semantics, also known as strong exception safety or no-change guarantee: Operations can fail, but failed operations are guaranteed to have no side effects so all data retain original values.

Basic exception safety: Partial execution of failed operations can cause side effects, but invariants on the state are preserved. Any stored data will contain valid values even if data has different values now from before the exception.

Minimal exception safety also known as no-leak guarantee: Partial execution of failed operations may store invalid data but will not cause a crash, and no resources get leaked.

No exception safety: No guarantees are made. (Worst level of exception safety)

Exception handling Patterns

Here is the list of patterns and questions defining the problems ( For the complete exposition visit here)

Error Object
What characterizes an error? How to structure and administrate error information?

Exception Hierarchy

How to structure error types? What role does inheritance play in the structuring of errors?

Error Traps
What indicators are useful to detect erroneous situations and where to install the traps in the application code?

Assertion Checking Object

How to implement Error Traps in an object oriented language without using a generative approach?

Backtrace

How to collect and trace useful information for the system developers or the maintenance team, so that it supports them by the analysis of the error situation? Especially, if we have no or limited access to the stack administered by the system itself.

Centralized Error Logging

How do you organize exception reporting so that you can offer your maintenance personnel good enough information for analyzing the branch offices problems?

Error Handler
Where and how do you handle errors?

Default Error Handling
How do you ensure that you handle every possible exception correctly (no unhandled exception and limited damage)?

Error Dialog

How to signal errors to an application user?

Resource Preallocation
How to ensure error processing although resources are short?

Checkpoint Restart
How do you avoid a complete rerun of a batch as a result of an error?

Exception Abstraction
How do you generate reasonable error messages without violating abstraction levels?

Exception Wrapper

How do you integrate a ready-to-use library into your exception handling system?

Multithread Exception Handling

How to schedule exceptions in a multithread environment?

Eric Lippert's classification


Writing good error handling code is hard in any language, whether you have exception handling or not. When Eric Lippert first classifies every exception into one of four buckets which he labels fatal, boneheaded, vexing and exogenous. You can read the entire article here.

Fatal exceptions are not your fault, you cannot prevent them, and you cannot sensibly clean up from them.

Boneheaded exceptions are your own darn fault, you could have prevented them and therefore they are bugs in your code. These are all problems that you could have prevented very easily in the first place, so prevent the mess in the first place rather than trying to clean it up.

Vexing exceptions are the result of unfortunate design decisions. Vexing exceptions are thrown in a completely non-exceptional circumstance, and therefore must be caught and handled all the time.

And finally, exogenous exceptions appear to be somewhat like vexing exceptions except that they are not the result of unfortunate design choices. Rather, they are the result of untidy external realities impinging upon your beautiful, crisp program logic.

Best practices

Here is the gist of what Daniel Turini talks in his article Exception Handling Best Practices in .NET.


Plan for the worst

-Check it early
-Don't trust external data
-The only reliable devices are: the video, the mouse and keyboard.
-Writes can fail, too

Code Safely

-Don't throw new Exception()
-Don't put important exception information on the Message field
-Put a single catch (Exception ex) per thread
-Generic Exceptions caught should be published
-Log Exception.ToString(); never log only Exception.Message!
-Don't catch (Exception) more than once per thread
-Don't ever swallow exceptions
-Cleanup code should be put in finally blocks
-Use "using" everywhere
-Don't return special values on error conditions
-Don't use exceptions to indicate absence of a resource
-Don't use exception handling as means of returning information from a method
-Use exceptions for errors that should not be ignored
-Don't clear the stack trace when re-throwing an exception
-Avoid changing exceptions without adding semantic value
-Exceptions should be marked [Serializable]
-When in doubt, don't Assert, throw an Exception
-Each exception class should have at least the three original constructors
-Be careful when using the AppDomain.UnhandledException event

No comments: