Skip to main content
Preslav Rachev

Image Credits: Mats Hagwall / Unsplash

Much of the code I have seen in my career is a good example of the Pareto principle. 80% of the code in any codebase would deal with the “happy path” (what the software is expected to do), while the other 20% is left for tackling errors, exceptions, and edge cases.

Naturally, when learning to program, we encounter the if-else statement (which happens to be present in most popular languages), and our brains immediately associate the if with the happy path and the else with the edge case scenarios. It is a natural safety mechanism - wrap your entire block of code in a big if, and you’ll sleep better at night, knowing you’ve protected it from inappropriate inputs. For every other case, there’s that tiny else at the end, right?

Unfortunately, it often leads to code that looks like this:

if (someConditionIsMet) {
	// ...
	// ...
	// ...
	// 100 more lines of code
	// ...
	// ...
	// ...
	// and 100 more
	// ...
	// ...
	// ...
} else {
	// Now, take care of that edge case
}

return someResult

One issue here is that the edge case handling is left at the very end, which makes it easy to overlook when adding code to the block above it. I bet most people reading the code won’t even recall that the else exists until and edge case forces them to dig deeper.

But even that is something I could live with if it wasn’t that people tend to replicate the same pattern on multiple levels. As a result, code in real life looks more like this:

if (someConditionIsMet) {
	// ...
	// ...
	// ...
	// 100 more lines of code
	// ...
	// ...
	// ...
	// and 100 more
	if (someOtherConditionIsMet) {
		// ...
		// ...
		// ...
		// 100 more lines of code
		// ...
		// ...
		// ...
		if (yetAnotherConditionIsMet) {
			// ...
			// ...
			// ...
			// 100 more lines of code
			// ...
			// ...
			// ...
		} else {
			// Now, take care of that edge case
		}
		// ...
		// ...
		// ...
	} else {
		// Now, take care of that edge case
		return someOtherResult
	}
	// ...
	// ...
	// ...
} else {
	// Now, take care of that edge case
}

return someResult

That’s right - code nesting is a massive footgun and the easiest way to bring unnecessary complexity to any codebase. The human brain can only deal with a few different things at a time, so when faced with having to dig multiple levels deeper, it’s easy to forget an important thing that happened one level above. It’s one of the most frequent reasons I would bring back a pull request. Our business processes are complex enough; why must we make our lives even more complicated?

I am not the first to address this phenomenon - in fact, it even has a name. Jeff Atwood coined the term Arrow Code for this sort of deep nesting almost two decades ago.

Luckily, the solution is pretty simple.

Ditch that Else. Invert the logic. Tackle the edge case first. #

What if instead of that massive if-else block, we decided to get rid of the else and took care of it first? If we don’t expect something to happen regularly, wouldn’t it be better to check for it first, and return right away if it did? I mean it - tackle the small edge case and return early if you have to; otherwise, leave the happy path at the top level of your function.

if (!someConditionIsMet) {
	// Take care of that edge case first
	return someResultOrNothing
}

// The happy path can continue without a guarding block
// ...
// ...
// ...
// 100 more lines of code
// ...
// ...
// ...
// and 100 more

return someResult

The same idea can get replicated with multiple edge cases too:

if (!someConditionIsMet) {
	// Take care of that edge case first
	return someResultOrNothing
}

if (!someOtherConditionIsMet) {
	// Take care of that edge case first
	return someResultOrNothing
}

if (!yetAnotherConditionIsMet) {
	// Take care of that edge case first
	return someResultOrNothing
}

// The happy path can continue without a guarding block
// ...
// ...
// ...
// 100 more lines of code
// ...
// ...
// ...
// and 100 more

return someResult

So, how about ditching that else?

References #

Why should you return early?
When I started my journey as a computer programmer, I had written my code in various way. In most cases, I translated requirements into specific conditions and statements, but I hadn’t taken too much care of readability or quality of my code. “It works, that’s it” – and the code base grew and grew in time. Thousands of written methods later, I had discovered that a lot of these little pieces of logic could look better if I reverse some condition within them.

Have something to say? Join the discussion below 👇

Want to explore instead? Fly with the time capsule 🛸