views:

502

answers:

9

Most advice concerning error handling boils down to a handful of tips and tricks (see this post for example). These hints are helpful but I think they don't answer all questions. I feel that I should design my application according to a certain philosophy, a school of thought that provides a strong foundation to build upon. Is there such a theory on the topic of error handling?

Here's a few practical questions:

  • How to decide if an error should be handled locally or propagated to higher level code?
  • How to decide between logging an error, or showing it as an error message to the user?
  • Is logging something that should only be done in application code? Or is it ok to do some logging from library code.
  • In case of exceptions, where should you generally catch them? In low-level or higher level code?
  • Should you strive for a unified error handling strategy through all layers of code, or try to develop a system that can adapt itself to a variety of error handling strategies (in order to be able to deal with errors from 3rd party libraries).
  • Does it make sense to create a list of error codes? Or is that old fashioned these days?

In many cases common sense is sufficient in developing a good-enough strategy for dealing with errors. But does anyone know of a more formal/"scholarly" approach?

PS: this is a general question, but C++ specific answers are welcome too (C++ is my main programming language for work).

Edit
On second thought, perhaps a set of guidelines is sufficient after all, as long as it leaves no areas uncovered.

The advice to "handle the error if you can or propagate" answers a lot of questions for me.

Update
Actually, after some thinking I find that it boils down to three simple rules:

  1. Use a top-down approach when it comes to catching errors. Write 'try/catch' blocks in all your code's entry points: main(), event listeners, timer callbacks, etc... Log the error inside the catch blocks.
  2. With these "safety nets" in place you can now throw without having to worry about unhandled exceptions. Make 'throw' your default response to (exceptional) error conditions. Just make sure you have RAII Protection.
  3. Where needed write extra catch handlers closer to where the exception is thrown. This will often not be necessary.

This strategy seems answer most of my questions:

  • How far should I let my errors propagate? Until the top-level handlers. Refine for specific cases.
  • Where should I do logging? In the catch blocks.
  • Should I adapt a error handling strategy that can adapt itself to different error handling strategies of other libraries? If the library returns an error code then you can throw an exception.
  • Does it make sense to create a list of error codes? Not sure, probably not.
A: 

The first question is probably what can you do about the error?

Can you fix it (in which case do you need to tell the user) or can the user fix it?

If nobody can fix it and you are going to exit, is there any value in having this reported back to you (through a crash dump or error code)?

Martin Beckett
+8  A: 

Is logging something that should only be done in application code? Or is it ok to do some logging from library code.

Just wanted to comment on this. My view is to never logg directly in the library code, but provide hooks or callbacks to implement this in the application code, so the application can decide what to do with the output from the log (if anything at all).

RA
A: 

How to decide if an error should be handled locally or propagated to higher level code?

If the exception breaks the operation of a method it is a good approach to throw it to higher level. If you are familiar with MVC, Exceptions must be evaluated in Controller.

How to decide between logging an error, or showing it as an error message to the user? Logging errors and all information available about the error is a good approach. If the error breaks the operation or user needs to know that an error is occur you should display it to user. Note that in a windows service logs are very very important.

Is logging something that should only be done in application code? Or is it ok to do some logging from library code.

I don't see any reason to log errors in a dll. It should only throw errors. There may be a specific reason to do of course. In our company a dll logs information about the process (not only errors)

In case of exceptions, where should you generally catch them? In low-level or higher level code? *Similar question: at what point should you stop propagating an error and deal with it?*

In a controller.

Edit: I need to explain this a bit if you are not familiar with MVC. Model View Controller is a design pattern. In Model you develop application logic. In View you display content to user. In Controller you get user events and call Model for relevant function then invoke View to display result to the user.

Suppose that you have a form which has two textboxes and a label and a button named Add. As you might guess this is your view. Button_Click event is defined in Controller. And an add method is defined in Model. When user clicks, Button_Click event is triggered and Controller calls add method. Here textbox values can be empty or they can be letters instead of numbers. An exception occur in add function and this exception is thrown. Controller handles it. And displays error message in the label.

Should you strive for a unified error handling strategy through all layers of code, or try to develop a system that can adapt itself to a variety of error handling strategies (in order to be able to deal with errors from 3rd party libraries).

I prefer second one. It would be easier. And I don't think you can do a general stuff for error handling. Especially for different libraries.

Does it make sense to create a list of error codes? Or is that old fashioned these days?

That depends on how will you use it. In a single application (a web site, a desktop application), i don't think it is needed. But if you develop a web service, how will you inform users for errors? Providing an error code is always important here.

If (error.Message == "User Login Failed")
{
   //do something.
}

If (error.Code == "102")
{
   //do something.
}

Which one do you prefer?

And there is another way for error codes these days:

If (error.Code == "LOGIN_ERROR_102") // wrong password
{
   //do something.
}

The others may be: LOGIN_ERROR_103 (eg: this is user expired) etc...

This one is also human readable.

JCasso
A: 

Here is an awesome blog post which explains how error handling should be done. http://damienkatz.net/2006/04/error_code_vs_e.html

How to decide if an error should be handled locally or propagated to higher level code? Like Martin Becket says in another answer, this is a question of whether the error can be fixed here or not.

How to decide between logging an error, or showing it as an error message to the user? You should probably never show an error to the user if you think so. Rather, show them a well formed message explaining the situation, without giving too much technical information. Then log the technical information, especially if it is an error while processing input. If your code doesn't know how to handle faulty input, then that MUST be fixed.

Is logging something that should only be done in application code? Or is it ok to do some logging from library code. Logging in library code is not useful, because you may not even have written it. However, the application could log interaction with the library code and even through statistics detect errors.

In case of exceptions, where should you generally catch them? In low-level or higher level code? See question one.

Similar question: at what point should you stop propagating an error and deal with it? See question one.

Should you strive for a unified error handling strategy through all layers of code, or try to develop a system that can adapt itself to a variety of error handling strategies (in order to be able to deal with errors from 3rd party libraries). Throwing exceptions is an expensive operation in most heavy languages, so use them where the entire program flow is broken for that operation. On the other hand, if you can predict all outcomes of a function, put any data through a referenced variable passed as parameter to it, and return an error code (0 on success, 1+ on errors).

Does it make sense to create a list of error codes? Or is that old fashioned these days? Make a list of error codes for a particular function, and document it inside it as a list of possible return values. See previous question as well as the link.

Tor Valamo
+4  A: 

My view on logging (or other actions) from library code is NEVER.

A library should not impose policy on its user, and the user may have INTENDED an error to occur. Perhaps the program was deliberately soliciting a particular error, in the expectation of it arriving, to test some condition. Logging this error would be misleading.

Logging (or anything else) imposes policy on the caller, which is bad. Moreover, if a harmless error condition (which would be ignored or retried harmlessly by the caller, for example) were to happen with a high frequency, the volume of logs could mask any legitimate errors or cause robustness problems (filling discs, using excessive IO etc)

MarkR
As @RA mentioned, I believe it can be useful for some libraries to provide a mechanism for attaching a logger from higher level code. For example this may be handy if you are writing a console application that supports different verbosity levels.
StackedCrooked
A: 

My two cents.

How to decide if an error should be handled locally or propagated to higher level code? Handle errors you can handle. Let errors propagate that you can not.

How to decide between logging an error, or showing it as an error message to the user? Two orthogonal issues, which are not mutually exclusive. Logging the error is ultimately for you, the developer. If you would be interested in it, log it. Show it to the user if it is actionable to the user ("Error: No network connection!").

Is logging something that should only be done in application code? Or is it ok to do some logging from library code. I see no reason why libraries can't log.

In case of exceptions, where should you generally catch them? In low-level or higher level code? You should catch them where you can handle them (insert your definition of handle). If you can't handle them, ignore them (maybe someone up the stack can handle them..).

You certainly shouldn't put a try/catch block around each and every throwing function you call.

Similar question: at what point should you stop propagating an error and deal with it? Should you strive for a unified error handling strategy through all layers of code, or try to develop a system that can adapt itself to a variety of error handling strategies (in order to be able to deal with errors from 3rd party libraries). At the first point that you can actually deal with it. That point may not exist, and your app may crash. Then you'll get a nice crash dump, and can update your error handling.

Does it make sense to create a list of error codes? Or is that old fashioned these days? Another point of contention. I'd actually say no: one super list of all error codes implies that that list is always up to date, so you can actually do harm when it's not up to date. It's better to have each function document all the error codes it can return, rather than have one super list.

Terry Mahaffey
A: 

I'm changing my design and coding philosophy so that:

  1. If all runs smoothly, as expected, no errors generated.
  2. Throw an exception if something different, or unexpected happens; let the caller handle it.
  3. If it can't be resolved, propagate it up a higher level.

Hopefully, with this technique, the issues that get propagated to the User will be very important; otherwise the program tries to resolve them.

I'm currently experiencing issues that get lost in the return codes; or new return codes are created.

Thomas Matthews
A: 

The book "Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries" book by Krzysztof Cwalina and Brad Abrams has some good suggestions on this. See chapter 7 on Exceptions. For example it favours throwing exceptions to returning error codes.

-Krip

Krip
The general practice in .NET is not appropriate for C++. In .NET, and probably also in C++ code distributed as source, the correct thing for a library to do is provide both variants. For C++ libraries distributed as binaries on Windows, exceptions are NEVER the right way, because there's no standardized ABI for C++ exceptions. C++ templates open a lot of possibilities not available to .NET, such as inlining an application-provided conversion function which can return the error code directly, wrap it in a type of the application's choosing, or throw.
Ben Voigt
+1  A: 
  1. Always handle as soon as possible. The closer you are to its occurrence the more chance you have to do something meaningful or at the least figure out where and why it happened. In C++, it is not just a matter of context but being impossible to determine in many cases.

  2. In general you should always halt the app if something buggy occurs that is a real error (not something like not finding a file, which is not really something that should count as an error but is labeled as such). It's not going to just sort itself out, and once the app is broken it will cause errors that are impossible to debug because they have nothing to do with the area they occur.

  3. Why not?

  4. see 1.

  5. see 1.

  6. You need to keep things simple, or you will regret it. More important to handling bugs at runtime is testing to avoid them.

  7. It's like saying is it better to centralize or not centralize. It might make a lot of sense in some cases but be a waste of time in others. For something that is a loadable lib/module of some kind that can have errors that are data related (garbage in, garbage out), it makes tons of sense. For more general error handling or catastrophic errors, less.

Charles Eli Cheese