Saturday, August 21

Exception Obfuscation: Hiding what really went wrong

In my last entry, I discussed my colleague's plea to pollute [sic] our precious four-year-old over-one-hundred-thousand-lines JDK-1.1-compliant code base with some fancy schmancy new collections APIs. Well, this week he's at it again with what he calls "exception chaining" and I call "exception obfuscation."


public Exception(Throwable cause)
Constructs a new exception with the specified cause and a detail message of (cause==null ? null : cause.toString()) (which typically contains the class and detail message of cause). This constructor is useful for exceptions that are little more than wrappers for other throwables (for example, PrivilegedActionException).

cause - the cause (which is saved for later retrieval by the Throwable.getCause() method). (A null value is permitted, and indicates that the cause is nonexistent or unknown.)

Yup, it's another whiz bang new feature in the JDK 1.4 API. You can take a perfectly good exception and obfuscate it inside another exception. And what for pray tell does my colleague want to use this shiny new bauble? He wants to take all those pesky methods that declare multiple exceptions, like IOException and SocketException and SQLException and wrap them up into a neutral exception like SomethingBrokeException so that the calling classes don't have to declare catch blocks for all the possible types of exceptions; they can just catch the one generic exception.

"Well," you might ask, "why doesn't he just catch Exception? That will satisfy all the declared exceptions." Yes, but it will also encompass some undeclared exceptions, and when they get thrown, we want them to propagate, because they might indicate the system is in an unstable state, and in some cases it's better to crash than to keep processing and possibly cause even more damage.

OK, so he's got a valid complaint and a viable solution. What's the problem? The problem is what about calling classes (either present or future) that care about the type of exception thrown? What if the calling class wants/needs/knows-how to handle IOExceptions differently from SQLExceptions? Now it's catching a generic SomethingBrokeException, but it cares about what broke!

"Well," my colleague argues, "if the calling class really cares about what type of exception was the root of the problem, it can call the new getCause() function." So the point is that we can replace a try/catch block with an if/else block, and the calling classes that don't care about the problem can just catch the generic exception and thus save the programmer a little typing. Poppycock, I say!

I'm pretty big on analogies. Being a CTO, I commonly have to explain complex technological concepts to non-technical people (like my clients, and the CEO), and I always do so through analogies. So allow me to address this issue likewise: It's like you're a general contractor and I've hired you to build a new room onto my mansion. You've fitted the new room with contemporary five-prong electrical outlets so I can take advantage of the next generation of appliances. But since I don't have any such appliances, you're also offering to sell me some new-five-prong-to-old-three-prong adapters. Gee, thanks a lot! Now I've got a house with two different types of electrical outlets, and I have to keep a box full of adapters in the closet for special occasions. You've taken something that worked just fine, didn't make it work any better, and just made it harder for me to use with my existing tools, so that it might be easier to use with future tools.

No comments: