Flattening the Happy Path
Picture from ilovehz on Freepik

The following is among my favorite clean code patterns: flattening the happy path.

It is very easy to learn, yet instantly increases the quality of your code.

Let’s have a look.

Anti-pattern vs Best Practice

Don’t exit the happy path early in your control flow

class Example {
    void antiPattern() {
        if (thing != null) {
            if (thing.getState() == ILLEGAL_STATE) {
                throw new IllegalStateException("Thing was in illegal state.");
            }

            return doSomething(thing);
        }

        throw new NullPointerException("thing was null");
    }
}

Check preconditions and illegal conditions first, then handle happy path

class Example {
    void goodPractice() {
        if (thing == null) {
            throw new NullPointerException("thing was null");
        }

        if (thing.getState() == ILLEGAL_STATE) {
            throw new IllegalStateException("Thing was in illegal state.");
        }

        return doSomething(thing);
    }
}

We can see here that the happy path is both, on the lowest level of indentation of the method body. That means it is not wrapped inside inner if statements or loops. And it is at the bottom of the method body.

Advantages

The flat happy path pattern has many advantages over otherwise structured method bodies.

It is easy to read and reason about. Following this pattern all over the code base helps the reader to first identify and understand the preconditions. It reveals the intention of the programmer of what illegal and legal states to expect.

Code control flow handling is explicit. It forces the programmer to think first about preconditions and narrow them down. Beginners often forget to handle errors, as they primarily care about the happy path and not the error conditions.

The pattern reduces cognitive load. With the pattern in place, there is no need to spend too much energy to understand under which condition the code may fail or succeed during runtime.

The code is less error-prone. In low quality code, bugs occur when state handling and flow control get mixed up and follow no clean pattern. Nevertheless, in case of programming errors, it is usually easier to debug the flat happy path pattern than the anti-pattern. Once you realize that you have missed a precondition, you just add it to the upper part where invariants are enforced.

Basing your code on this structure, you can compound other good practices easily. Enforcing preconditions early and systemically has been mentioned already. Separating stateless from stateful methods, extracting core logics into a separate class or using narrow-but-deep interface design. To just name a few.

Newer post

Active vs passive software development

When software developers enter in management positions, they are often lacking to not code actively. In this article I argue that passive software development through delegation is indeed a valuable exercise. It still makes you a better developer.

Active vs passive software development