Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Handling Errors and Exceptions. Part 1 – Intro.

4.67/5 (2 votes)
22 Sep 2015CPOL5 min read 9K  
Have you ever seen that recommendation to avoid exception handling like this: Well, indeed, I agree that this kind of code looks pretty bad. But is it helpful to know only that? No, it is not. The problem of proper errorexceptions handling is very far from being popular.

Have you ever seen that recommendation to avoid exception handling like this:

try { 
    //do something 
} 
catch(Exception ex) { 
}

Well, indeed, I agree that this kind of code looks pretty bad. But is it helpful to know only that? No, it is not. The problem of proper error\exceptions handling is very far from being popular. There are some articles in the Internet, but I feel like there’s a lack of articles on that topic and this problem should be popularized among at least junior and middle developers.

What does an “Exception” mean?

If you noticed, the title of the article differentiated the notions of an “error” and an “exception”. Many programmers still think that they are the same, but this is very far from the truth (though, nobody knows where is the ultimate truth regarding errors\ exceptions handling problem).
The simplest way to explain the difference between errors and exceptions is to say that “errors are returned, but exceptions are thrown”. So, the original meaning of throwing exceptions is to fail fast, unwinding the stack, until the proper handler (catch-block). The most important part here is “unwinding the stack”, this is the main difference from returning an error. The most appropriate cases in which exceptions should be thrown are:

  • improper API invocation
  • program reached critical circumstances in which it can’t continue to execute

As Eric Lippert said here and there:

  • Exceptions are noisy when you’re debugging.
  • An exception is a goto without even a label.

Eric Lippert continues, “Their power comes at an extremely high cost; it becomes impossible to understand the flow of the program using only local analysis; the whole program must be understood. This is especially true when you mix exceptions with more exotic control flows like event-driven or asynchronous programming. Avoid, avoid, avoid; use exceptions only in the most exceptional circumstances, where the benefits outweigh the costs.”

Practical problems of handling Exceptions

How many times your program failed because of an unexpected exception thrown from an API you invoked?
Lets consider an extremely simple case: you have to read a file from the disk and notify the user if something goes wrong. Somewhere in your code you’ll use, say, File.ReadAllBytes(). Now the question is what exceptions are you going to catch? (don’t forget the notification requirement)
Well, if we want to adhere to the principle of catching only those exceptions we are aware of, then we need to know about what exceptions can be thrown from a particular API call. Which potential exceptions mean that “we failed to read a file”?
One would think that we can handle FileNotFoundException and maybe a couple of others. After a week, or a month, user will see either suddenly closed application, or a message like “Something went wrong, sorry. Call to someone who can help you.” The irony here is that no one can even enlist all potential exceptions from a particular API call, especially if that call drills down to the system, or trying to acquire system resources. The second problem with handling specific exception types is hidden by versioning of a software. Clients of the first release may be sure that they can just handle exception of type A from a call to method Do(), but in the next version the functionality of Do() was extended and now it can throw exception of type B. As a result, clients are broken. These problems are the reason why C#-team didn’t implement so-called checked exceptions.

Can we just catch them all?

It’s a temptation to put balls on all that difficult stuff connected with proper handling of errors and exceptions. Despite of the good chances I could be considered by some readers as an idiot, or something like that, I’ll say that sometimes it can be a reliable and sufficient for success strategy to just catch all exceptions. In my opinion, as always in engineering, we can’t just blindly state that “we should never ever write try{}catch(Exception ex){}“. In my opinion, you should reason about your errors\exceptions handling strategy when you start developing a new application, bearing in mind a couple of things:
1. What sort of application are you going to develop? Is it a nuclear weapon managing software? Is it a software for a device intended to struggle with cancer? Is it a cardboard game? Is it notepad-like app? Obviously, requirements for reliability are different for such applications.
2. What is the proficiency level of your team? Are you absolutely sure, that your team is ready to deal with proper error\exceptions handling? It’s very, very hard to write this kind of code. I’m not joking. At first you have to be sure, that you are surrounded by decent professionals, otherwise it may be better to rely on the “catch them all” approach.
3. The size of an application. Well, I can’t define the upper boundary in number of code lines, when you start to suffer from the “catch them all” approach, the only thing I can say, that there are tons of good (at least not worse than other) software, which rely on “catch them all” approach, or plain error codes. Now, I participate in a project where we use “catch them all” strategy, our solution consists of over 100k lines of code and we don’t suffer much (we suffer from other things, rather than improper exceptions handling).
So, generally speaking, you should think at first about whether you can afford yourself the easier life, or not. The choice is up to you. There is no single right answer for all cases.

Summary

Well, I hope now you realize the extent of the problem. Actually, no one knows how to do errors\exceptions handling in a good, painless way. As always in engineering, there’s just no a silver bullet.
At first I thought that I would say all I want to about this problem in a single article. But now I feel that this is enough just for the intro. The most useful info from the practical perspective dedicated to handling errors\exceptions will be considered in the next part. Stay tuned.

P.S.
A couple of interesting links concerning the discussed problem:


Filed under: .NET, Best Practices, C#, CodeProject, Design

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)