More on swallowing and throwing...

ctodx
26 July 2006

I've had some excellent replies to my original post on exception handling in our UI controls and some of the points made have given me much food for thought. I'd have to say though that John Gooding's reply most closely fits my view of things.

If I may summarize the main points:

  • Our code should never show a message box to display an exception message
  • Adding the ability to log exceptions is good
  • The way it works at the moment (swallow exceptions for certain code paths) is acceptable in some cases (for simple apps, to fire off some default behavior)
  • There should be some way for the developer's code to decide whether an exception should be swallowed or rethrown
  • We should create and use our own exception classes

Well the first item goes without saying, really. For example, I hate it if I'm baldly informed that a list index was out of bounds (so, what exactly do you want me to do about it?), and I certainly wasn't advocating that our UI controls should display a message box for a WinForms application!

No, in my opinion, this is solely within the purview of the application developer. The poor application developer (and that means our customers, of course!) must test his application enough to understand the problems that can occur, and have programmed defensively against those exceptions he feels the application can automatically deal with or recover from. The others may be exposed to the user as a general "The application has encountered an error and needs to close" dialog box, perhaps with a More... button that shows the original exception and stack trace with a "phone home" capability to upload it automatically.

Second, exception logging. To be honest, for me this is extremely important. Last job I had before Developer Express was for a company that wrote software that ran on many machines across the enterprise. Code was written in C++, VB6, and C#. If something went wrong we had to know about it and we had to have good enough logging to understand what led up to the problem so that we could trace through the code flow. All the user would see would be a dialog saying an unexpected error occurred and that they should look for more details in the log.

I'm reminded of a problem I encountered in CodeRush 1.x. I wanted to change the behavior so that certain single key templates wouldn't be expanded. I made the change in the options dialog, pressed OK, and went back to my editing. Lo and behold it was as if my changes hadn't taken place. I went back into the options dialog made the same changes and pressed OK again. No change in the editor: those single key expansions continued to occur. I was just about to fire off an email when I remembered Mark talking about the messages log. I found it, discovered what the problem was (directory not found, essentially), fixed it, and everything was fine.

That story has two morals: first, if an error occurs, it's best to let the user know about it somehow. Not by throwing a cryptic exception message in the user's face, but by displaying something to say that his task didn't complete and that further information is available somewhere about the exact cause of the problem. Second, have a log where all exceptions get recorded. Including stack traces if possible.

(We implemented the latter at my previous job: a complete recording of the information in a .NET exception, including stack traces and recursing through inner exceptions, and cycling through all errors in a SQLException instance. To say it saved our bacon is an understatement. It also goes without saying that, by having this code in a production environment, we discovered many bugs that had simply been hidden by a previous catch-and-swallow strategy (including a situation where we weren't properly impersonating an authentication token the first time through some code.)

So I definitely like the idea of having some kind of notification interface through which our controls can log exceptions before discarding them. It'll be up to the app developer then to implement a logging facility that we can call when we catch an exception (a first chance handler). I don't particularly want to go as far as having a generic logging interface through which we can log informational messages or warning messages, since we'd then get into a huge discussion about what we should log and when (on entry into a method? before we raise an event? Etc). Say something like this in our code:

try {
  // do something risky
}
catch (Exception ex) {
  DxLogger.GetInstance.LogException(ex);
}

 
where DxLogger is some kind of Singleton class or interface we provide that you can extend using event handlers, or some such mechanism.

Even better, perhaps:

// somewhere in your startup code..
DxExceptionProcessor.ProcessException += new ExceptionProcessor(MyFirstChanceExceptionProcessor);

// in our code
try {
  ..blah..
}
catch (Exception ex) {
  if (DxExceptionProcessor.GetInstance.ShouldRethrow(ex))
    throw;
}

Which would give you the opportunity to not only log the exception, but also to decide whether a given exception is bad enough to rethrow and thereby, presumably, terminate the application or at least get some other code involved in processing it (say the appdomain's exception handler).

In fact that last design gives us a good start on providing a solution to most of the points made.

  • If you don't want to handle exceptions caught in our code, don't provide an exception processor. Our code will work as before.
  • If you want to log exceptions but otherwise do nothing about them, write an exception processor that does exactly that and returns false so that our code doesn't rethrow.
  • If you want to log exceptions and also make decisions about which errors to swallow then write an exception processor that does exactly that. The problem is you won't have that much information to make good decisions at this point (remember, this will happen in a low level in our code, not at a higher task-based level in your code).
  • If you want to log exceptions and also make sure they propagate up the call stack, then write a processor that returns true (to rethrow) after logging.

Comments?

Free DevExpress Products - Get Your Copy Today

The following free DevExpress product offers remain available. Should you have any questions about the free offers below, please submit a ticket via the DevExpress Support Center at your convenience. We'll be happy to follow-up.
No Comments

Please login or register to post comments.