- 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 Location and Context
The execution flow in an application typically looks like illustrated in the diagram below.
|Program flow from some boundary (root) and downwards through the modules and components.|
The diagram is a bit simplified, but I think you get the point.
The execution starts a some root point. A root point could be:
- The main() method of a standalone application (Java, C#, Scala etc.)
- A web service entry point.
- A Servlet, JSP, ASPX, PHP page etc.
- Something else...
Exactly what the root of execution is, is not that important. Some applications may also have multiple roots. What is important to note is that the execution flows from a root and downwards into the application code. Depending on what the application is doing, the execution will take different paths down through the code. Nothing surprising here.
At some point in the application an exception may get thrown. An exception will bubble up the call stack until caught and handled. Nothing new or interesting here either.
What is interesting to notice, is that Component 1.2 is called by both Module A and Module B. If an exception occurs in Component 1.2 then it may have to be handled differently depending on whether Module A or Module B called Component 1.2.
For instance, lets say that Component 1.2 is a file loading utility. Module A is then configuration file loader, and Module B is a user file loader, as illustrated below:
|Config Loader and User File Loader both call the FileLoader component, but handles exceptions differently.|
If the application cannot load one of its configuration files, this may be a very serious error. The application operators (if any) should be notified of such an error.
If on the other hand, a user enters an invalid file name and the file loader (Component 1.2) cannot load it, this may not actually be such a serious error. Of course the user should be notified of the error, but it may not actually be necessary to notify the application operators. The user can just correct the file name, and retry the file load action.
As you can see, Component 1.2 (
FileLoader) cannot by itself determine if failing to
load the file is a serious error, or just a natural possibility due to what the application does.
Error Location and Context Defined
Here I will define the two concepts error location and error context in a bit more detail:
- Error Location
The location in the code where an error occurs, and an exception is thrown.
The execution path leading to the error location.
Both error location and error context influence how you should handle an exception thrown from the error location.
This is a bit at odds with the common exception handling advice, that "the code closest to where the error occurred, knows best how to handle it". You have just seen, that this is not always the case.