On every project I’ve worked on, one of the first things I have to do is work out why an exception was thrown. Usually, that first error message doesn’t contain enough information to help me solve the problem. At this point I congratulate the previous developer of the system on getting so far with such sloppy error handling.
After congratulating myself, I move on to reviewing the project’s approach to exception handling. I like to do this globally if possible, to ensure that the approach is consistent throughout the project, and so that I can have reasonably expect to see the information I need next time something goes wrong.
Good exception handling and reporting is critical to the success of any software project. Since the bulk of a project’s lifetime is spent in bug fixing and maintenance, good error reporting can make this phase of a project much less time consuming that it might be. With a stack trace, I can immediately tell where the fault occurred, and who was calling that code. In most cases, that’s enough information to understand the problem.
I’ve completely refactored the exception handling of a couple of medium-sized projects; in doing so, I’ve observed a few rules of thumb make this process a breeze if followed. I’ll try to summarize them here:
Don’t swallow nested exceptions
Change this:
try { ... }
catch (Foo e) { throw Bar() }
to this:
try { ... }
catch (Foo e) { throw Bar(e) }
The first exception thrown is always the most important for software developer; it provides information about the underlying cause and location of a failure. When you discard it this way, determining what happened is next to impossible.
In case you’re wondering, the following is not a good substitute:
try { ... }
catch (Foo e) { throw Bar(e.getMessage()) }
Tempting, but count yourself lucky if you get any useful information this way; you’ll probably get a vague message, or perhaps nothing at all. And you just lost the most useful piece of information: the stack trace of the underlying error.
Posted by rattigan