Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I'm currently doing a code review and one of the things I'm noticing are the number of exceptions where the exception message just seems to reiterate where the exception occurred. e.g.

throw new Exception("BulletListControl: CreateChildControls failed.");

All three items in this message I can work out from the rest of the exception. I know the class and method from the stack trace and I know it failed (because I've got an exception).

It got me thinking about what message I put in exception messages. First I create an exception class, if one does not already exist, for the general reason (e.g. PropertyNotFoundException - the why), and then when I throw it the message indicates what went wrong (e.g. "Unable to find property 'IDontExist' on Node 1234" - the what). The where is in the StackTrace. The when may end up in the log (if applicable). The how is for the developer to work out (and fix)

Do you have any other tips for throwing exceptions? Specifically with regard to the creating new types and the exception message.

share|improve this question
3  
Are these for log files or to present to the user? –  Jon Hopkins Dec 23 '10 at 12:14
1  
For debugging only. They may end up in a log. They would not be presented to the user. I'm not a fan of presenting exception messages to the user. –  Colin Mackay Dec 23 '10 at 13:12
    
+1 Excellent question! wish I'd thought of it. –  Michael K Dec 23 '10 at 15:05

4 Answers 4

I'll direct my answer more to what comes after an exception: what's it good for and how should software behave, what should your users do with the exception? A great technique I came across early in my career was to always report problems and errors in 3 parts: context, problem & solution. Using this dicipline changes error handling enormously and makes the software vastly better for the operators to use.

Here's a few examples.

Context: Saving connection pooling configuration changes to disk.
Problem: Write permission denied on file '/xxx/yyy'.
Solution: Grant write permission to the file.

In this case, the operator knows exactly what to do and to which file must be affected. They also know that the connection pooling changes didn't take and should be repeated.

Context: Sending email to 'abc@xyz.com' regarding 'Blah'.
Problem: SMTP connection refused by server 'mail.xyz.com'.
Solution: Contact the mail server administrator to report a service problem.  The email will be sent later. You may want to tell 'abc@xyz.com' about this problem.

I write server side systems and my operators are generally tech savvy first line support. I would write the messages differently for desktop software that have a different audience but include the same information.

Several wonderful things happen if one uses this technique. The software developer is often best placed to know how to solve the problems in their own code so encoding solutions in this way as you write the code is of massive benefit to end users who are at a disadvantage finding solutions since they are often missing information about what exactly the software was doing. Anyone who has ever read an Oracle error message will know what I mean.

The second wonderful thing that comes to mind is when you find yourself trying to describe a solution in your exception and you're writing "Check X and if A then B else C". This is a very clear and obvious sign that your exception is being checked in the wrong place. You the programmer have the capacity to compare things in code so "if" statements should be run in code, why involve the user in something that can be automated? Chances are it's from deeper in the code and someone has done the lazy thing and thrown IOException from any number of methods and caught potential errors from all of them in a block of calling code that cannot adequately describe what went wrong, what the specific context is and how to fix it. This encourages you to write finer grain errors, catch and handle them in the right place in your code so that you can articulate properly the steps the operator should take.

At one company we had top notch operators who got to know the software really well and kept their own "run book" that augmented our error reporting and suggested solutions. To recognise this the software started including wiki links to the run book in exceptions so that a basic explanation was available as well as links to more advanced discussion and observations by the operators over time.

If you've had the dicipline to try this technique, it becomes much more obvious what you should name your exceptions in code when creating your own. NonRecoverableConfigurationReadFailedException becomes a bit of shorthand for what you're about to describe more fully to the operator. I like being verbose and I think that will be easier for the next developer who touches my code to interpret.

share|improve this answer
    
+1 This is a good system. Which is more important: Being sure the information gets across, or using short words? –  Michael K Dec 23 '10 at 15:04
1  
+1 for i like the solution of including , context,problem,solution –  WebDev Dec 23 '10 at 17:03

As a general rule, an exception should help developers pinpoint the cause by giving useful information (expected values, actual value, possible causes/solution, etc.).

New exception types should be created when none of the built-in types make sense. A specific type enables other developers to catch a specific exception and handle it. If the developer would know how to handle your exception but the type is Exception, he won't be able to handle it properly.

share|improve this answer
    
+1 - expected values vs actual values are extremely useful. In the example given in the question, you should not simply say that a method failed, but why it failed (basically, the exact command that failed, and the circumstances that caused the fail.) –  Felix Dombek Dec 23 '10 at 13:45

The things you want to be looking for to "add" to the exception are those elements of data that are not inherent in the exception or the stack trace. Whether those are part of the "message" or need to be attached when logged is an interesting question.

As you've already noted, the exception proably tells you what, the stacktrace probably tells you where but the "why" may be more involved (should be, one would hope) than just going to peer at a line or two and saying "doh! Of course". This is even more true when logging errors in production code - I've all too often been bitten by bad data thats found its way into a live system that doesn't exist in our test systems. Somethig as simple as knowing what the ID is of the record in the database that's causing (or contributing) to the error can save significant amounts of time.

So... Either listed or, for .NET, added to the logged exceptions data collection (c.f. @Plip!):

  • Parameters (this can get a bit interesting - you can't add to the data collection if it won't serialize and sometimes a single parameter can be surprisingly complex)
  • The additional data returned by ADO.NET or Linq to SQL or similar (this can also get a bit interesting!).
  • Whatever else might not be apparent.

Some things, of course, you won't know you need until you don't have them in your initial error report/log. Some things you don't realise you can get until you find you need them.

share|improve this answer

Don't create new types if you can help it. They can cause extra confusion, complexity and lead to more code to maintain. They may make your code had to extend. Designing an exception hierarchy requires a lot of though and testing. It's not an after thought. It's often best to use the built in language exception hierarchy.

The content of the exception message dependents on the receiver of the message - so you have to put yourself in that person's shoes.

A support engineer will need to be able to identify the source of the error as quickly as possible. Include a short descriptive string plus any data that can help troubleshoot the issue. Always include the stack trace - if you can - this will be the only true source of information.

Presenting errors to general users of your system depends on the type of the error: if the user can fix the problem, by providing different input for example, then a concise descriptive message is required. If the user can't fix the problem, then it's best to state an error has occurred and log/send an error to support (using guidelines above).

Also - don't throw up a big "HALT ERROR!" icon. It's an error - it's not the end of the world.

So in summary: think about the actors and use cases for your system. Place yourself in those user's shoes. Be helpful. Be nice. Think about this up front in your system design. From the perspective of your users - these exception cases and how the system handles them, are just as important as the normal cases in your system.

share|improve this answer
4  
I disagree. There are many good reasons to implement your own exceptions when the language API doesn't cover your exact needs. One reason is that in a method where multiple things may fail, you can write different catch clauses for different types of exceptions, where you can react to the exact problem. Another is that you can separate multiple layers of exceptions representing different layers of abstraction, where the exact layer that an exception belongs to can be encoded in its type. Just using "Exception" or "IllegalStateException" and a message string doesn't help much there. –  Felix Dombek Dec 23 '10 at 13:51

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.