Ever came across an ASP.NET error page because of a missing configuration entry? Been faced with the question “shouldn’t we at least catch the exception and log it? Just to make sure?” or some statement like “you should catch every exception and throw a new one”? Stumbled over the notorious catch-all or a class whose methods all do exception handling a bit differently? Well, those are symptoms of a missing error management strategy.
It’s actually quite frustrating how often that happens. What’s more, many developers don’t even notice that there is something amiss; they’re quite content dealing with exception on a method by method basis, without taking the bigger picture into account. Or they are very well aware that there is something amiss, but they don’t get it. They know they have to do something, so they set out to do a bit here, a bit there, but not with a clear goal in mind, nothing consistent, only aiming to treat the symptoms and quite regularly overdoing it.
I really don’t remember what first brought the analogy with baseball, of all things, to my mind. Perhaps it was the notion that ‘try’, ‘catch’ and ‘throw’ could be outcries during some ball game, combined with my lack of understanding of baseball (a bit stretching, but that’s how mind twists work). Perhaps it was the idea that many developers do exception handling like they would play baseball if they had never heard of the game.
Stretching or not, that analogy is something I can work with. (And my apologies to everyone who loves and understands that game for everything that follows! ;-))
A Quick Evaluation of … Baseball.
Baseball, like all games has rules. Rules that put the various players into roles they have to fulfill. Most importantly, rules you have to learn if you want to play along. Some are fairly basic “mechanics” of the game: The pitcher throws in the general direction of the batter and the catcher does what his title implies (or so wikipedia tells me).
Some rules are obvious by looking at the game: If the batter hits that ball, he drops the bat and runs, while those guys on the field are trying to catch the ball.
Some rules are rather convoluted and you may have to study some booklet to grasp them; like what the hell is an inning and how do they determine who is winning?
That’s about as much as I understand about baseball. But then, would I want to play baseball, I knew I had a lot to learn before even thinking of entering the field. What rules apply to pitching. What roles do those guys on the field have, what are their responsibilities. How to score points. When to move on to the next round. When does the game end. Under what conditions do the rules change. What is considered foul play and when does it lead to aborting the game.
And this is a surprisingly similar situation to exception handling… . Except that many who play that game play it as if there isn’t even the need for rules, much less asked for them (or have been told about them – which is telling something, too).
Back to Exceptions
The mechanics of exceptions revolve around try/catch/throw and the implied syntax, exception hierarchies, and understanding the runtime behavior. Knowing that much can be expected from every developer and is usually not an issue at all. It is however only just the mechanics, and merely a starting point to proper exception handling.
In the same way the current situation in a game does play a role in baseball (e.g. the batter’s decisions on whether to play safely or to take some risk), the location and situation of a particular code fragment plays a role in the decision on what to do with regard to exceptions. Dealing with them only in the scope of the current code fragment is simply too shortsighted. One has to ask about the overall application strategy to exception handling and how that respective fragment fits into that strategy.
The caveat is: You have to have such a strategy. And defining that strategy should be part of coming up with an application architecture. Yes, exception handling is an architectural topic, not a coding issue.
Exceptions vs. Errors vs. Complexity
As I said, exception handling is an aspect of static and dynamic application architecture, just like security, transaction handling, state management, whatever. But there’s one thing that sets exception handling apart, and that’s dealing with the unexpected, the contradiction of having to deal with what you didn’t think of in the first place.
Exceptions come into play under three different conditions:
- First, as a means to break the current control flow, say to abort a request upon redirection to another page. This is intended behavior in a regular situation, not even an error.
- Secondly in cases that disrupt the logically correct operation, but you actually planned for that disruption. Say you rely on a file to exist but you know that someone might screw up, so you handled that case, despite the fact that during regular operations it shouldn’t happen at all. This is an error, but an intended behavior in an expected irregular situation.
- The third condition is the worst of all: Something unintended happens, something you cannot do anything about. It may arise as ArgumentException (telling you that the developer screwed up) or may be as TypeLoadException (telling you that the environment is on quicksand). In any case this is a purely unintended error and the only thing you can assume about the state of your application afterwards is, that it is not safe to assume anything.
An application architecture should provide provide rules on how to handle these conditions. Add questions like how to deal with the consequences, or deal breaker like parallelism, asynchronicity, or loose coupling, as well as reasonable demands regarding data consistency and error compensation… . And this becomes quite a complex task.
The paradoxical situation however is: Complexity is the very source of errors. Adding complexity is like pouring gasoline into the fire. As developers we already have to deal with the complexity of the problem domain. An exception management strategy should kick in if we fail in that regard. And if he is already doing something wrong, how can we rely on him to do something other (that isn’t even in his line of thinking) right? We can’t!
So, a good exception handling strategy needs to solve that contradiction: The need to deal with different exception conditions on one side. Making things easy for the developers, at the same time not relying on them to do things correctly on the other. Not a small task, indeed. And perhaps this is the very reason that exception handling is usually dealt with so poorly.
OK, this was a lengthy introduction and the actual story is even longer. However I thought it prudent to point out the bigger problem and generally raise the awareness for the topic. Of course I also enjoyed playing with that baseball analogy…😉. Anyway, in the interest of some readers not interested in such musings I split this one in two distinct posts. This one to explain the problem and make you curious, the next one to provide a solution. Stay tuned if I caught your attention.
PS: Special thanks to Karl for the permission to use his pictures…
PPS: There’s actually more to say about baseball than just baseball. Have a look here, German readers may find a more thorough explanation here. And no, it’s got nothing to do with software development😉