Monday, January 24, 2005

Exception-based code antipatterns

To continue the topic of exception-based code, there are cases when bad code is easy to spot. For example, this snippet is almost always inappropriate:
  try:

# do something
except: # catch any possible exception
pass # and just ignore it
Semantically, this is equals to error-code-based code with no error checking. It has valid use cases but there are a few.

Another antipattern, more coupled specifically to Python:
  try:

# do something
except Exception, e:
# handle it
Most of the time you should catch specific exception class(es) instead of base Exception class. The problem with this approach is that in Python, everything is reported through exception mechanism, including syntax errors, keyboard interrupts, program exit, memory errors, etc. And usually you don't want to catch these kind of exceptional conditions.

This catch-all is often a sign of a sloppy programming, where a programmer was too lazy to list actual exception classes to catch or the calling code is known to raise all kind of exception and there is no documented exception class to look for (which is often the case for poorly written/abstracted modules).

Unfortunately, advise to catch specific exception classes has a drawback as well. When the calling code is updated it could raise new types of exception and thus handling code must be updated as well. For third-party code, this risk often could be mitigated by abstracting external interface and re-warping (and documentin) use of exception classes.

Exception-based code

In a recent post, Raymond Chen writes about an important difference between plain old code from pre-exceptions age, that used to return special error codes to indicate errors and modern exception-based code:
...it is extraordinarily difficult to see the difference between bad exception-based code and not-bad exception-based code.
And then he concludes:
Consequently, when I write code that is exception-based, I do not have the luxury of writing bad code first and then making it not-bad later. If I did that, I wouldn't be able to find the bad code again, since it looks almost identical to not-bad code.
Arguably, exception-based code is safer because it fails early, as soon as exception is raised at the point of failure. Contrast this with error-checking code where sloppy programming style (not checking for a error code explicitly) could result in an obscure failure in a seemingly unrelated part of the program much later. On the other hand, sloppy programming style for exception-based code is more damaging, as you'd have to review the whole codebase line-by-line to find all potential places where exception-handling code need to be added.

When I started practicing TDD I often wrote simplest possible implementation that was arguably too simple with regard to exceptions. As I discovered over time, usually it's more
efficient to write necessarily exception-handling code (if any) right from the start. If I'm in hurry or not sure how to handle a possible exception I at least put in an assertion guard.

But the killer feature of exception-based code is this: programmer is freed from error-checking most of the time. While you do have to be careful while writing code and every line of code is a potential source of an exception, typically there is a relatively few places where you add
exception-handling code: external resources' handling, inter-system interfaces, input/output with the outer world, etc.

Overall, exception seems to be a net benefit. Result is a more stable program (fails early) with less efforts (fewer places to do error handling). Yes, it's hard to write a good exception-based code, harder then write a good error-code-based code but who said it's going to be easy?

There is no such thing as a free launch, after all.