Result vs Exception

Jun 18, 2018
-
5
minute read

When working with business or network integrated software, errors are inevitable. It’s been compellingly argued that exceptions should not be used for control flow. It’s also critical to communicate the cause of the error and known solutions. One of the possible solutions this leads to is using a Result data structure. Let’s look at how this differs from the conventional use of exceptions.

Every exception should be caught right at the source and encapsulated in a Result with a descriptive message.

Every error-possible part of the system must return nothing but Results.

Safe parts of the system do not need to use Results.

Every application response message should be a Result.

Every operation which depends on another Result must itself return a Result.

Using Results instead of throwing exceptions is not an easy fix. It takes discipline and intentionality. It will change your codebase substantially, perhaps as much as migrating from Asynchronous code to Synchronous. The error-possible parts of your system will all be explicit, and working with error-possible workflow steps can be handled with cleaner syntax using methods or extension methods for Result.

Why use an enum for ResultStatus?

It is best for a program to have a finite list of possible errors it expects. In a well-designed program, all common types of expected errors are known and explicitly expressed. Whether an enum, or a code, or a string is used is not important. What is important is a clear description of the type of error, and easy discoverability of all possible general error types.

Why is an enum or string better than a strongly-defined type? Because they aren’t really a different type of thing, typed exceptions are simply aliases. Also, not using strongly-typed exceptions prevent the abuse of language features like catching particular types of exceptions and using them for control flow.

Using results means that errors are handled at the source instead of imperatively by the calling code. It eliminates early returns from methods. It leads to code that is more declarative, since the control flow is explicitly handled by the Result.

Should you use Results instead of Exceptions?

I’ve been working with Results in microservices for more than 2 years. I’ve tried various permutations and implementations. Results are best for microservices, since there are many types of errors that can occur, and those can be a huge pain if they aren’t communicated effectively across boundaries with clarity. There are some tradeoffs, however.

Results

Takes a fair bit of work to setup and use

Works best with Functional Programming techniques

Makes all possible errors explicit and well-communicated

Significantly reduces error handling code duplication

Much better client/server error communication and troubleshooting

Exceptions

More familiar for most developers

Is the prevailing design paradigm for many popular libraries

Leads to simpler and smaller code when exceptions are genuinely rare

Makes it harder to find and discover the true source of errors, even when using StackTrace

Works best with imperative programming styles

For standalone applications with fewer integrations, it’s probably better to just use exceptions. For game development and tightly-scoped libraries, it’s better to use neither results nor exceptions. When working with distributed software where transient errors are frequent, and cross-service debugging and tracing is harder, using Results is the best way to go.