Exception Handling Anti-Patterns

Exception handling seems easy. But, done poorly, it can cause problems of its own or worse, it can cause problems that hide other problems.

Eating Exceptions

The worst anti-pattern is eating exceptions. This is when an exception is caught, nothing (or minimal logging) is done to handle the exception, and processing continues.

try {
... Do Stuff ...
catch {
Debug.WriteLine("Oh no, an exception occurred.")

This pattern causes some of the hardest to find bugs. Especially when the try block calls code in other classes.

Why are these bugs so nasty? The failure occurs leaving an object (or objects) in an invalid state. The failure is ignored and processing continues assuming everything is good. This can lead to corrupted data, and other, hard to reproduce exceptions.

Finding these exceptions is onerous; usually requiring some luck as well as skill.

What’s the fix for this pattern? 99+% of the time , the best fix is to remove the try/catch block. Let the exception be handled by the application-level handlers; let the stop once an object is in an invalid state.

One of the first things I do when I start on a new codebase is to remove try/catch blocks that are not:
1. Application-level exception handlers
2. Handling an exception
This sometimes causes some angst from the other developers. But it will also slowly (or, sometimes, not so slowly) expose those hard-to-find bugs that have been lurking so that they can be fixed.

Losing Exception Information

Another common problem is losing track of some of the critical information about the exception, most commonly, the stack trace.

Let’s assume we are doing some database update code, and we need to handle exceptions to issue a rollback.

var transaction = new Transaction(connection);
try {
    ... update the database ...
catch (Exception e) {
    throw new Exception($"Issued rollback {e.Message}");

In this example, the stack trace is lost. Does that matter?

It can when you are trying to find and fix the bug. Assume you are using Entity Framework and SQL Server. One common exception is an EntityException (or a descendant) with the message:

String or binary data would be truncated. The statement has been terminated.

Finding the problem behind this error is a challenge in the best of circumstances. Finding it without knowing which update caused the problem is that much more difficult.

Fortunately, fixing this problem is easy. Instead of appending the original exception message, send the entire exception

var transaction = new Transaction(connection);
try {
    ... update the database ...
catch (Exception e) {
    throw new Exception($"Issued rollback", e);

Now, assuming the application level exception handler provides stack traces, finding the statement that caused the problem is easy.

And, like the previous anti-pattern, I search for references to the Message property of any exception when working on a new codebase. And I refactor to pass the entire exception because the information being lost is too important.

c# #region Tags and Why I Don’t Like Them

I’m back to the Microsoft stack (ASP.NET MVC, c#, etc.) for the first time in a while. One of the things When I worked with it previously, I hated #region markers in any code file. Now, since I’m the lead, I have a policy of deleting them where I find them. No exceptions. I did tell my team that I would do this but I never really explained why.

The #region was originally used to segregate generated code from the code written by the developer. These days are over, partial classes totally eliminated this usage.

Today, I see two main uses of #region tags.

First, they are used to group types of things. Region tags are put around:

  • Properties
  • Public Methods
  • Private Methods

The second common usage is grouping related things:

  • Around an event and it’s delegate
  • All methods related that talk to the database

So why don’t I like #region markers?

Regions Hide Code

When a class is opened in Visual Studio, and it has #region tags, the #region tags are collapsed by default. In other words, at least some of the implementation of the class is hidden when the class is opened. This can make it difficult to find what you were looking for. And, expanding the regions can take you out of your train of thought by preventing you from going straight to what you were looking for.

Regions Hide Size

One of the more common design problems is a class that does too much. The feedback from scrolling and navigating a large class is one of the items that helps determine it is time for a refactor. Regions eliminate this feedback, they can make a class that is way too large not feel that way. But that feeling is an illusion, as soon as any serious work needs to be done, the size of the class will quickly become an obstacle to maintaining the class.

Regions Hide Complexity

The hidden code can also hide complexity. If a class is doing too much, when it’s responsibilities are muddled, regions can be used to group that functionality to make things appear more maintainable. But again, it is an illusion. Because as soon as something not insignificant needs to change, especially if that change will cross regions, the region approach will make the change more difficult.

Let’s Make Maintainable Code

One of our goals when developing most systems should be delivering maintainable code. Regions work against this.

Microsoft has acknowledged that #region tags should not be used any longer. Today, the default settings for StyleCode, do not allow #region tags to be used. In other words, Microsoft no longer believes #region tags need to be used. So neither should you.