Getting error handling right

Yan Babitski
Dec 15, 2019 · 6 min read

Software engineers write programs that work. Great software engineers write programs that work in almost any condition.

You just spent 5 minutes typing in the name, addresses, and lots of other things in an online government form and got the “Server connection closed” message after clicking on “next.” You check in to a flight using a self-check-in terminal, and after finally solving the quest of using its interface, you got “Sorry, an error happened.” You are making a money transfer using a mobile app and step into an elevator where there are no signal and app freezes.

Image for post
Image for post

Not good enough error handling in software could cause a mild annoyance, frustration, and could even create problems that would take hours to resolve. And not only that. Bad error handling makes the product look unfinished, raw, sloppy. It undermines users’ trust.

So it’s good to have some thought put into “what could go wrong” scenarios and have them handled. It’s good to have reliable software that just works and doesn’t require the whole team of support engineers to put up fires over and over again. And part of this effort is to keep the code clean and have a consistent approach to error handling.

We’ve already discussed the difficulties with using the most common vehicle to deal with errors — exceptions, and also looked at what good does it give. Based on the observations, let’s try to come up with a few ideas on how to make our software reliable.

Idea #0. Guidelines (aka code style)

A natural way to get some of the accidental complexity is not to have code style. Then different projects across the organization or even different parts of the same projects would have different styles: variables named differently, different indentations, etc… It’s bad for two reasons:

  • Each time you are looking at code, you have to spend a little bit of time figuring out what is what. If code style is uniform and you see MAX_DELAY in Java or kMaxDelay in C++ you know it’s some constant
  • Each time you encounter some rule, you personally don’t like you might spend some time “fixing” it.

That’s why pretty much every company develops or uses style guides. The main value from it is not that it chooses “the best” style but that it chooses it. Uber’s “standard code style” puts it nicely:

The the whole point of standard is to avoid bikeshedding about style. There are lots of debates online about tabs vs. spaces, etc. that will never be resolved. These debates just distract from getting stuff done.

Image for post
Image for post

So it could be useful to develop guidelines for handling errors and stick to it. Though guidelines themselves are just the beginning.

It should be easy to do the right thing: libraries for relevant languages with all utility classes should be provided, as well as dev tools to take care of trivial things like indentations and variable naming.

And it should be difficult to do the wrong thing: there should be both technical (presubmit checks that won’t allow submission if there are style errors) and organizational (code review) mechanisms to enforce code style.

We could use the same approach for error handling. Have a few guidelines when dealing with error scenarios, so error handling becomes a matter of following these rules.

Idea #1. Use both exceptions and statuses

The simplest example is to pass JSON provided by the user. Honestly, we don’t treat “user-provided JSON is invalid” as something exceptional — it’s a normal flow of things. One could argue that we could have two methods instead: “validate” and “process.” That’s a fair point, and it’s probably correct from an idealistic point of view. But in practice that would entail requiring the user to call two methods instead of one and making a data class for that JSON — ok things to do, but extra work. And we would still have cases where we want to return either value or error.

Some languages have native support for this pattern (e.g. Scala’s Try or Go’s multiple return values), for some language a custom should be created (though it’s shouldn’t bee too difficult): e.g. Google’s StatusOr.

Idea #2. Use exceptions for exceptional cases only

Idea #3. Have a set of standard errors and use it everywhere

Image for post
Image for post
Questions to answer when dealing with error

What if our guideline is the following: “always use standard errors?” That’s two fewer questions to think about (3 for Java). And not only that.

With custom errors, there would be additional problems:

  • Discover already present exception/error status. Would custom exception classes be located in utils? Or exceptions? Or maybe errors? Is it in our project or in some sort of common shared library? Which common library: <project-name>-common, just common, or maybe we have common-errors? I’m sure you had this situation.
  • Deal with similar or even completely equivalent statuses or exceptions. In this module we use mapper.errors.NotFoundError , but this library returns geo.statuses.NotFoundErrorStatus. So we should probably check and convert the latter to the former.

These problems are eliminated entirely if a set of standard error statuses/exceptions is used. E.g. use one from Google. Is the file absent? Return NOT_FOUND. Invalid data was provided — INVALID_ARGUMENT. Request to withdraw submitted before money arrived — FAILED_PRECONDITION. Sometimes the choice might be tricky, but these 15 codes should work for 90% of the cases.

For the remaining 10% of cases, we would have to create custom error codes/exceptions.

Idea #4. Treat custom error same as a custom class loader

Exceptions or error codes should be treated similarly to custom class loaders or memory allocators. Or custom collection type. You won’t create CustomerArrayList so don’t create CustomerNotFoundException. Errors are part of the infrastructure, not business logic.

All these measures are supposed to help with accidental complexity, help to focus on important things, and not on solving riddles of implementation details.

Though probably not all of these ideas will work for you as is — no silver bullet. There is no single technical answer to get error handling right.

Getting error handling right is partially about technical details: what works best for your project and codebase, but a big part of it is about communication and leadership: how to get other engineers on board, come up with good enough approach, and do it in a reasonable amount of time. The ideas here are not ideal, but it could be a good starting point to work out a different set of guidelines that would fit your team and organization.

The Startup

Medium's largest active publication, followed by +756K people. Follow to join our community.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store