Monday, June 30, 2008

Don't hide my error! A note on business apps and exception handling

Suppose you get some dlls to use by your foreign fellow developer team. But there you go, who would have guessed. The thing throws an error. In the real world you'd look at the stack trace, the exception type, the inner exception and the error message for starters.
I have had architects tell me "but we cannot give you this information, we use the same classes for our client", and more annoyingly "this is what business applications do: hide the error from the user".
First off, I agree that no user should receive a stack trace or too cryptic error message. A user would be better served with a tip on how to possibly resolve the issue (maybe the file is locked, so he could be advised to close all other copies of the file before saving over it for example).
But, and here it javascript:void(0)
Bericht publicerencomes: I'm not a user. I'm a developer. The project is in development. I am entitled to either a clearly written error that helps me resolve any programming errors I make, or at least to a full stack trace so i can at least attempt to figure out where it went wrong. I am entitled to an inner exception and an exception type.

So, on to a real world example, wich is also the worst case scenario, sadly:

01. Peanuts p = new Peanuts();
02. try
03. {
04. ErrorCausingClass ecc = new ErrorCausingClass();
05. ecc.CausePossibleErrorByReadingTheDatabase();
06. ecc.CausePossibleErrorBySendingEmailWithBusinessLayer();
07. ecc.CausePossibleErrorByConnectingToCommunicationFoundationService
08. } catch (Exception e)
09. {
10. p.Eat();
11. throw new Exception(e.Message);
12. }

in this scenario, when an exception occurs on line 7, the error is caught on line 8, and a new error is generated (see the 'new'? that means 'new error'). So what does 'new error' mean?
a) its a generic (untyped) error. all you know its an error, but not what type of error, for example a FilenotFound when reading the configs, but you wouldn't know.
b) the stacktrace is gone. the actual error did not occur on line 7, but somewhere deeper in the class used on that line.
c) the inner exception is gone. Have you ever encountered an error message "check inner exception for details". Well, it's "null" now. Oops, no details.
d) the location where the error occurred is gone too. The line registered for the error returned by this piece of code is line 11, where the new error is generated.
e) the error message is returned and eventually bubbled up to the user.

To recap: useless for developers, users get to see needless error message as it cannot be used for debugging.

The solution is plain and simple:
01. Peanuts p = new Peanuts();
02. try
03. {
04. ErrorCausingClass ecc = new ErrorCausingClass();
05. ecc.CausePossibleErrorByReadingTheDatabase();
06. ecc.CausePossibleErrorBySendingEmailWithBusinessLayer();
07. ecc.CausePossibleErrorByConnectingToCommunicationFoundationService
08. } catch (Exception e)
09. {
10. p.Eat();
11. throw e;
12. }

In this example, no error information is lost to the developer, and no-one is counting on it that the error is ready-for-use by the end user. A developer can provide a logical, sense-making error message for a few different types of error as the error type is not lost. Debugging is a lot easier with the stacktrace and inner exception still present.

What's even better then in some cases? Take a look at this (assume this is in a function called 'DoStuff')

01. Peanuts p = new Peanuts();
02. try
03. {
04. ErrorCausingClass ecc = new ErrorCausingClass();
05. ecc.CausePossibleErrorByReadingTheDatabase();
06. ecc.CausePossibleErrorBySendingEmailWithBusinessLayer();
07. ecc.CausePossibleErrorByConnectingToCommunicationFoundationService
08. } catch(TimeoutException te)
09. {
10. p.Eat();
11. throw new DoStuffFailedException("DoStuff failed due to a timeout. Check the inner exception for details", te);
12. }
13. } catch (Exception e)
14. {
15. p.Eat();
16. throw new DoStuffFailedException("Do stuff failed. Check the inner exception for details.", e);
17. }

In some cases it's preferrable to wrap a new custom exception around the original exception. This is mostly the case when a larger, logical part has failed, or when you will be handling other errors in identical ways. For example, if you custom implement a login system, a good practise would be to not return a 'FileNotFound' or a Timeout' that creates the inability to login, but you would focus on the inability to login, so throw a LoginFailedException. Developers use the inner exception to log and debug the problem. As close as possible to the user interface, the actual messagebox can contain a custom message tailored to the user. Wich could also be based on the inner exception, that is up to the developer of the UI.

A good practise when using smart clients or WCF is that the web service does not return detailed error information to the client. However, generally this can be enabled or disabled easily through config. Disabling detailed error information while development is taking place is asking for people saying your service doesn't work and they can't fix it.

Conclusion:
Developers should never be deprived of the information needed to solve the actual issue. If an application is written to hide all the exception information, developers using the dll will end up using something else. If you re too lazy/dont have enough time to write useful messages for the developers to use, keep the original error at the very least. Don't pretend they don't need it and don't hide behind the fact that a business application usually doesn't show the message to the user. Nowhere does that imply that an error has to be masked by an new one and all useful information thrown away.

nOOb

Being actually a newbie with the Visual Studio IDE I was wondering how to change my default application icon to a more favourable one... say.. nicer one. 'On with it!' I thought and sailed through the various searchengines and wondered about the great answers to the simple question:
'How can I change the shortcut icon for my Application in VS2005?'

My favourite:
Create a shortcut on Desktop and choose 'Change Icon' then choose the program you want the icon from.
The most harebrained:
Replacing the standard App.ico in the VS.
And the most obvious:
Go look in the Helpfile

And the easy one (really obtained through deduction from my Borland projects):
Go to the 'Project'-menu, choose '[Projectname] Properties' and behold the 'Application' Tab with the magic 'Resources' at the bottom, containing 'Icon'. Change that and you have a neato (or not so neato) shortcuticon :)

Prepare for more discoveries in the world of VS2005 and C# (I was looking for some decent examples for delegates... and oh boy, there are so many, yet so absolutely not-helping) :)

Bye