Re: Exception handling
 
Andre Rothe wrote:
Hello!
I try to find some information about a best-practice exception
framework. Maybe this group can help me.
An application throws an exception within a low-level method, let us
say, within a database access layer. It has occured as reaction of a
wrong value given by the user. The method can throw the exception, the
next higher abstraction layer can rollback the associated database
operation and throw it up to the client application.
This is a bad pattern.
The low-level methods should through exceptions which indicate 
programmer error. Higher-level methods should validate *before* calling 
lower-level methods.  The high-level methods can either throw 
appropriate exceptions or directly report problems to the user.
The reason I advocate this pattern is because Low-Level methods 
shouldn't know or care whether their invocation is due to a user action, 
or an automated process, or something else.
Low-Level methods should be designed to report programmer errors and 
low-level interface problems (IO errors, DB errors, etc...)
Higher level methods should be task oriented (for example, "User 
requested a record")  The higher level method should verify that the 
user entered valid data, and that the record was returned correctly.
It may seem like a little bit of repeating yourself, but once you 
realize that the lower-level exception has a different purpose, you can 
get over the fact that you might write the same check in two places.
To avoid the duplication of "checks", you can create a predicate method 
somewhere that can be called by the lower-level method and the higher 
level method.  In the lower-level method, you can document in the 
contract that the precondition is "isValidFoo()" (for example).  This 
makes it a programmer error to call a method with a bad precondition.
Now, if the lower-level method throws an exception, it can be of three 
kinds:  High-Level Programmer error (bug: failed to verify 
precondition), Low-Level Programmer Error (bug: in the library), 
Exceptional Circumstance (i.e. IOException).  The first two should be 
reported to the user only as "There was an internal error handling your 
request", and the full stack-trace logged somewhere for reporting and 
reproducing.  The latter exception can be reported to the user with an 
appropriate message (eg. "Unable to communicate with database", or 
"Unable to open file")
Of course, this is all idealized. Sometimes it is infeasible to verify 
user-input before calling the lower-level method.  In which case, the 
lower-level method can still throw a "low-level" exception, but it 
should still be translated into "high-level" message by the higher level 
code.
I hope this all makes sense. I could go on further, but if I go on any 
longer and I'll have to break it into sections, gather references, add 
markup, throw and catch exceptions, etc... ;-)