15

Can you recommend a design pattern/approach to exposing/tolerating/recovering from system errors, Exception handling (Java, C++, Perl, PHP)?

Some errors need to be reported.

Some errors can be handled internally (by a retry or are inconsequential (can be ignored).

How do you structure the code to catch them?

But all errors need to be logged.

What best practises are there?

And for simulating them to be able to fully test components that are impacted by them?

General non-programming-language specific question applicable to several modern programming languages but would welcome example illustrations of patterns, approaches and philosophies in Java, C++, PHP and Perl.

(Also asked in stackoverflow: https://stackoverflow.com/questions/7432596/recommend-a-design-pattern-approach-to-exposing-tolerating-recovering-from-system but I thought it should be asked on programmers too because I think the programmers Q&A covers wider software/programming issues whereas stackoverflow is more about technical implementation IMHO).

3
  • 2
    To me your question seems far too general and open-ended to be answered effectively. Try to restrict it to some more specific case(s) and also to specific application types / environments (e.g. GUI app / server / ...). Commented Sep 19, 2011 at 14:24
  • See also stackoverflow.com/questions/937285/… Commented Sep 19, 2011 at 14:42
  • @Péter Török, mikera provides a good answer, likely to accept theirs. Commented Sep 19, 2011 at 19:11

3 Answers 3

17

Fail fast is a great design approach, and perhaps it can be counted as a pattern: http://en.wikipedia.org/wiki/Fail-fast

I've also found a number of principles to be useful:

  • Consider exceptions as part of the interface to each function / modules - i.e. document them and where appropriate / if your language supports it then use checked exceptions.
  • Never fudge a failure - if it failed, don't try to continue with some attempt to "assume" how to proceed. For example, special handling for null cases is often a code smell to me: if your method needs a non-null value, it should be throwing an exception immediately if it encounters a null (either NullPointerException or ideally a more descriptive IllegalArgumentException).
  • Write unit tests for exceptional cases as well as normal ones - sometimes such tests can be tricky to set up but it is worth it when you want to be sure that your system is robust to failures
  • Log at the point where the error was caught and handled (assuming the error was of sufficient severity to be logged) . The reason for this is that it implies you understood the cause and had an approach to handle the error, so you can make the log message meaningful.....
  • Use exceptions only for truly unexpected conditions/failures. If your function "fails" in a way that is actually expected (e.g. polling to see if more input is available, and finding none) then it should return a normal response ("no input available"), not throw an exception
  • Fail gracefully (credit to Steven Lowe!) - clean up before terminating if at all possible, typically by unwinding changes, rolling back transaction or freeing resources in a "finally" statement or equivalent. The clean-up should ideally happen at the same level at which the resources were committed for the sake of clarity and logical consistency.
  • If you have to fail, fail loudly - an exception that no part of your code was able to handle (i.e. percolated to the top level without being caught + handled) should cause an immediate, loud and visible failure that directs your attention to it. I typically halt the program or task and write a full exception report to System.out.
3
  • 1
    also fail gracefully - clean up before terminating if at all possible Commented Sep 19, 2011 at 18:23
  • +1 @mikera for clear points about what to consider. Likely accepted answer, I will leave open for a little longer for others to contribute. Commented Sep 19, 2011 at 19:08
  • +1 @Steve A. Lowe - for user-centred design. e.g. like saving files, not leaving temp files lying about. See my question about "data hygiene" as a related topic in my questions list. Commented Sep 19, 2011 at 19:10
5

Having worked with exceptions in Java and .NET AND after reading a lot of articles about how/when/why catching exceptions, I finally came up with the following steps that I go through in my head whenever I see a potential exception happening, or an exception I must catch (Java)... even if it never happens (sigh...). And it seem to be working, at least for me:

  1. Is there anything useful I can do with that exception, (except logging) ? If the answer is yes, write the workaround code, and if the workaround may throw exceptions, go to 2:
  2. Wrap the exception around a runtime exception, throw it, go to 3.
  3. In the higher-level class where a possible database/process transaction has been initiated, catch the exception, rollback the transaction, rethrow the exception.
  4. At the top-level class (which may be the one where the transaction has been initiated), log the exception using a logging framework such as slf4j (coupled with log4j for example), or log4net. If possible, directly email the exception to a distribution list that is composed of developers of the application.
  5. If there is a GUI, display an error message indicating in the most user-friendly way what caused the problem; do not display the exception/stacktrace, the user doesn't care and doesn't need to know it was a NullPointerException.

I should also add the step 0, where I am purposely throwing what I call a "business" exception (a new exception that I create by extending the "Exception" class) when some complex treatment cannot be executed because of data errors, BUT that are known to happen as they have been identified as exception cases during the analysis.

Except for the logging part, I fully agree with the points written by "mikera"; I will just add that the exception should be logged once only.

Also, the steps I listed may be different if what you are writing is an API/Framework. There, throwing well designed exceptions is mandatory to help developers understand their mistakes.

As for testing the exceptions, using mock objects you should be able to test nearly everything, be it exception-al or not, provided that your classes respect the "one class to do one thing" best practice. I also personally make sure to mark the most important but hidden methods as "protected" instead of "private" so that I can test them without too much hassle. Apart from that, testing exceptions is simple, just provoke the exception and "expect" an exception to occur by catching it. If you don't get an exception, then you have a unit test case error.

1
  • +1 @Jalayn for log4j mention as an approach, this is what I use so it reinforces it to know someone else is as well. Commented Sep 19, 2011 at 19:07
0

Build your objects the right way, don't worry about external factors. If you choose to take advantage of exceptions, then make your objects throw exceptions if they fail at something.

Once all your objects are working correctly, it should be fairly easy to come up with a clean error-handling responsibility hierarchy in your design.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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