How many times does “else if” appear in your codebase?
Let’s examine one way you can cut down on if-else statements in today’s episode of
software in 5 minutes a week.
The if-else statement is probably the first control flow construct you learned as a programmer.
And yet few things are as terrifying as diving into a legacy codebase swimming in nested,
cascading if-else statements.
Code with fewer if-else statements is generally less complex because it has fewer edge cases
that need to be tested, and code with fewer statements tends to have a more predictable
A program without any if-else statements or other conditional constructs is incredibly
straightforward to reason about, because data will always flow through the program in the
same way, even when the inputs and output change.
Now it’s unlikely you could eliminate all if-else statements from a program without
making readability worse off.
But a lot of if-else statements is a code smell, because they unnecessarily increase
the complexity and surface area for bugs.
So in the next few episodes of TL;DR we’ll cover some design patterns to cut down on
Today we’re examining some recursive code with several cascading if-else statements.
This resolve function walks through an object with nested objects, arrays and functions.
Given a deeply nested structure like this, it returns a similar structure, but where
the functions — like this one for the property favoritePlaces, which was originally a function
— have been invoked and replaced with their return value.
Now the logic for the resolve function is pretty terse: if the current structure is
an array or object, it recurses over the children.
If it’s a function, it invokes it and recurses over the return value.
Otherwise, it will just return the structure as-is.
Now these if-else statements aren’t complex per se, in fact it almost looks like it could
be a switch statement instead.
The problem is the testing conditions — that is, whether the data is a function, array
or object — can’t be described with strict equality, which we would need to use a switch
Hence, we had to stick with if-else statements instead.
So if the test condition is too complex for a switch statement, is there an alternative
that might at least move us away from if-else statements?
Well, the ternary operator is essentially an if-else expression.
While an if-else statement runs statements but doesn’t return anything, a ternary expression
evaluates and returns the value of one of the two expressions.
Let’s write a new version of the resolve function and convert the first if-else case
to a ternary: if the node is a function, the ternary evaluates to this case on the left,
but otherwise it will evaluate to the case on the right, that is, the node.
Like an if-else statement, only code in the matching case is evaluated — the other is
there is a stigma that ternaries are brittle and have finicky syntax rules.
But ternaries are actually more robust than an equivalent if-else statement because you
can only embed expressions, and not statements.
That makes it harder to sneak a side effect in, like setting a variable or forcing an
The main frustration for many developers is reading another developer’s one-liner ternary,
so it’s essential to space them out just like you would an if-else statement.
So instead of putting all this on one line, you should indent each case like this.
You’ll find this convention popular in the React community for switching between components.
With a little practice, a ternary becomes easier to read than the equivalent if-else
But what about those cascading else-ifs we had before?
Well since ternaries are just expressions, we can nest else-ifs in the last part of the
Well this is pretty awful to read, let’s fix that with some indentation.
Ternaries are designed to cascade, so the parentheses are actually unnecessary.
Next, let’s insert a new line after the question marks instead of before.
Then unindent each line that starts with a colon so it lines up with the first line.
And for the final else case, the colon will be on a line by itself.
Let’s practice reading this: if the node is a function, it returns the result of this
line, otherwise if node is an array, it returns the result of this line, and finally if the
node is neither a function nor an array, node is returned.
Wait a minute, we forgot to add a case for when the node is an object!
Well to add it, we can just insert it before the final else.
By formatting our ternaries like this, we can easily add and rearrange cases without
changing other lines or fretting about nested parentheses!
And now that resolve is only one statement, we can drop the curlies and return keyword
to make resolve an implicit returning arrow function.
In this style, I like to unindent the testing conditions one more level.
Now all of the test cases line up in one column, and all of the possible return values line
up in another.
From a control flow perspective, we’ve achieved the holy grail: the resolve function has no
variables, no early returns and no statements.
Now you might feel that this exercise of switching from if-else statements to ternary expressions
was purely aesthetic, but syntax is just a nice side benefit of the real benefits:
Whereas if-else statements are popular in imperative programming, which is built on
control flow, ternary expressions help us think about data flow and produce more declarative
Functions with a lot of statements tend to have several entry and exit points that new
team members need to parse through to keep from introducing a bug.
But functions composed of expressions tend to flow in the same way for any inputs.
Today, look through your codebase for cascading if-else statements where each case is roughly
the same, like returning a value or setting a variable, and try swapping the if-else for
And in the future, I would encourage you to default to nested ternaries, and make if-else
statements the exception.
You’ll find they force you to design your code better to begin with.
That’s it for today, you can get a transcript of today’s episode and catch up on other
great ways to craft exceptional code at JonathanLeeMartin.com/TLDR, and if you want to keep leveling up your craft,
don’t forget to subscribe to the channel for more rapid codecasts on design patterns,
refactoring and development approaches.