- Exception Handling Strategies
- Exception Handling Strategy - Overview
- Exception Handling Requirements
- Application Survival
- Notifying Relevant Parties
- Error Diagnostics and Reproduction
- Separation of Abstraction Layers
- More Readable and Maintainable Code
- Error Location and Context
- Error Causes, Types and Reactions
- Strategy Elements
- Error Detection
- Error Information Gathering
- Throwing Exceptions
- Propagating Exceptions
- Catching Exceptions
- An Exception Handling Strategy Template
- An Exception Class Template
- Throwing the AppException
- Propagating the AppException
- The ErrorInfo List
- Catching the AppException
- Avoid Exception Hierarchies
Error Diagnostics and Reproduction
To be able to correct an error in an application you must first be able to diagnose it. Diagnosing an error means determining the precise cause of the error. To diagnose an error from the error message alone is not always easy. Therefore it is often necessary to be able to reproduce the error, before you can determine its cause.
An effective exception handling strategy should take both diagnostics and reproduction into consideration. I will elaborate a bit on both here.
To determine the cause of an error you need to know:
- The exact location in the code where the exception occurred.
- The context in which that location in the code was reached. Some locations in your code are reachable via different execution paths. For instance, a utility method may be called from many different places in your application. You may need to know where the utility method was called from, in order to determine the cause of the exception.
- A sensible description of the error including any relevant variable values, including parameters, internal state variables (members, global variables etc.) and possibly external system state, for instance data in a database.
To be able to reproduce an error you need to know what external actions lead to the error. Sometimes the error is caused by a single action, and sometimes it is caused by a series of interdependent actions. For instance, your application may fail on the third of three related requests.
To reproduce the error you may have to go through all three requests, and to do that, you need information about each of these three requests.
It is not always easy to store information for multiple dependent steps. For instance, the two first steps (e.g. pages in a wizard-like flow in a web app), may succeed. Should you still log that, even if they succeeded? Then the third step fails. Now it would have been nice to have information about step 1 and 2, in order to reproduce the error, but perhaps you didn't log that information.
You cannot log every tiny little thing your application does. It would slow the application down a lot, and make the log files grow huge. Therefore, logging the full detail needed for reproduction is not always possible.