Thoughts on handling pesky errors 12 Dec, 2008
Whilst writing oodles of Java over the past few months, an old favourite—error handling—has come to the fore yet again: checked and unchecked exceptions, when to throw an error, when to log, when not to log, and so on and so forth. The upshot of such noodlesome navel-gazing is that any reasonable collection of code should have a carefully-thought out strategy for dealing with errors. And thinking about it more, of course Lotusscript is no exception.
(Hah! Do you see what I did there?)
Error Handling 101
Long-time readers will know that I look at errors and their handling quite a lot. I’ve certainly written about it before, even did a proper article once, which covered it a little (alas, for the sadly defunct ePro magazine). But one mistake I’ve found I used to make is to do something like this in every significant Lotusscript code sub / function I wrote:
Sub foo() On Error Goto oops ' Some code here Exit Sub oops: Call Messagebox("ERROR: " & Error$ & " in line " & Erl, 0, "Oops" Exit Sub End Sub
Hmmm. Not actually very useful, and actually oh-so-typical. Why is this example deficient? Well, how much time do you have? Not all errors are equal. Why cast off to an error handler which exits when all you’re hitting is a transient issue (e.g. missing data in a document loop)? Why throw errors indiscriminately at end-users? What do they care? Why throw up every piddling error regardless of its impact on the application? Consider context: this example is OK (if naff) in a Notes client, but what about web apps? It wouldn’t be very useful, and would spoil the line of your (otherwise beautiful) web site. Who looks at log.nsf on a regular basis for
MsgBox calls anyway?!
Feh, you get the idea. So, here’s a snippet of drop-in code for your error-handlers which might make developers think about their errors a little more:
oops: ' Just hurl the nasty error up that there stack Error Err, Error$ & " (" & Getthreadinfo(LSI_THREAD_PROC) & ", line " & Erl & ")" Exit Sub
Controversial eh? You read it right: just throw the damn error up the stack. Capture it where it matters, and deal with it appropriately (if at all). If you need to log it, do so in the invoking routine, not at the detailed level. Don’t worry about having a proper trace to the origin of the error, the
GetThreadInfo call above helps there (remember to include lsconst.lss).
If an error in a subroutine means the main routine cannot continue, well OK, that serious and you might even want to tell the user as much. But don’t rely on that. Users who hit errors tend to shrug and move on: they will not necessarily tell you something’s wrong, so be proactive. Ensure your code notifies whoever needs to know, or at least monitor your logging system of choice. Most importantly, handle the error, and remember that handling is not the same as reporting.
OK, so this is a tiny look at an important topic: please chip in with your thoughts. Having seen a lot of dysfunctional code (with and without error handling) over the years—some of it not even mine—I’m conscious that this is an area which needs some real thought, exploration, discussion and collaboration, so have at it.