When writing code, there is a certain feeling of importance with regards to one’s code. It should never stop. It should always execute to the end. It should not cast any exceptions, since my code can handle everything. Remember that a developers motto is “Everything is possible”. This leads to one of the biggest anti-patterns I have ever seen.
The catch everything, handle nothing anti-pattern. I honestly don’t know if there is a name for this, but this is what I call it at least. This is where a developer wraps everything that can cast an exception into a try-catch block. He then prints the exception, because hey, it’s an exception, and continues on his merry way. This is such a widespread anti-pattern, that a famous zen koan exists about it:
//Siddhartha Gautama, 450 BC
It’s a beautiful paradox, actually. Your code is so important, that it should never, ever, stop. But at the same time, whatever happens in SaveTheWorld(), isn’t really that meaningful, so we can continue anyway, whatever the result.
Let’s try to put this into a more concrete example you’ve probably seen before:
public List<Event> GetEvents(DateTime from, DateTime to)
var events = service.GetEvents(from, to);
if (events == null || !events.Any())
else return events;
Logger.Error("Failed to fetch events", e);
There are a million different things that are wrong with this method which could all be solved in a very simple way: it should not exist. Just call the service directly, and if it fails, let it fail.
For an inexperienced developer, this probably looks okay. All outcomes are taken into account; the service fails, no events are found, or some events are found. But nothing can be further from the truth.
For a starter, the call is ambiguous. What does a null result mean? Is it because no events where found, or because it failed? You are forcing who ever is consuming your class to delve into your code to find out. You should return an empty list. Or in this case, you should just return the result and trust whoever wrote the service class isn’t returning null himself.
And now we come to the next problem. You are forcing whoever is consuming your library to perform null checks, or in some cases even more than that, since they have no idea what your code actually did.
You see, whoever is consuming your library is usually dependent on it. Not only that, but they are dependent on the correct execution of that code. If your code fails, then by the definition of dependency, so should theirs. By eating the exception and returning null, you might be putting their system into a corrupt state.
So if we return to our previous example, we now only have return service.GetEvents(from, to). But what if it goes wrong, you might be shouting at your screen! What if it fails?! What if it can’t connect to the DB, or the service is offline, then what?!? Well, do you have a strategy for handling that exception? Like a meaningful one, and not a lie, like returning an empty list? If not, let someone else handle it.
Reasons to catch exceptions
There are though, reasons and strategies for catching and handling exceptions. Sometimes, you are iterating through some collection and just because one of the items failed, the entire process shouldn’t fail. You kinda need to keep iterating. Then inform someone! Write a relevant log entry. Just be aware that if you bombard developers with errors, they might just ignore it.
Another good reason is that the exception that just got thrown is not very informative. You might have something better to serve the user. Then it’s okay to catch that exception and re-throw a new one. There is something to note about it though: you are destroying the previous stack trace. This is not necessary a bad thing, you might want to simplify the problem for your user.
Be very careful about how you handle your exceptions. It’s very easy to be over zealous here and end up catching way more then you should, and putting your system in a corrupt state. I’ve recently written another post on the does and don’t’s (How do I spell this? Is this even a word?) of logging. This is closely related to exception handling, since you want the best logging messages you can get once your application does end up in a corrupted state.
Hope you enjoyed the article!