Untangling Nested Code
Tags: practices, programming, beginners
Published: 2018-07-16 14:55:31

---
title: Untangling Nested Code
published: true
description: How to identify the different forms of nested code and remove them.
tags: practices, programming, beginners
cover_image: https://thepracticaldev.s3.amazonaws.com/i/t8nrwvv2abxtnupivvou.png
---

I don’t believe in hard rules for writing code. You hear them often. Things like methods shouldn’t be more than __15__ lines. Methods should only have __one__ `return` statement. Indentation must be __4 spaces__. Such rules are too rigid.

In the real world code is much more fluid. Adhering to these hard rules distracts us from what really matters - _readability_. If my focus is strictly on the number of lines or `return` statements, I prevent myself from writing more readable code simply because it is a few lines "too long" or has more than one `return` statement.

Many of these hard rules attempt to address nested code. Nested code is hard to follow. Physically there’s more visual scanning with the eyes. Mentally, each level of nesting requires more overhead to track functionality. All of these exhaust a reader.

Nested code is mostly the result of conditionals. Since conditionals are the basis for all programming logic, we can’t very well remove them. We must recognize their effect on readers and take steps to minimize this impact.


## Getting back on top
To improve readability, we want to bring the code back to the top level. By nature, loops and conditionals have a nested structure. There's no way to avoid nesting within these blocks. However, we can avoid nesting beyond this structure.

Let's take a look at a few examples of nested code and practices for improving their readability.

### Empty blocks
You may not believe me, but I've seen the following code more than once:

```php
public function handle($request, Closure $next)
{
    if (env('APP_ENV') == 'development') {
        // do nothing...
    } else {
        if ($request->getScheme() != 'https') {
            URL::forceScheme('https');
            return redirect('https://www.example.com/' . $request->getPath());
        }
    }

    return $next($request);
}
```

That's right, an empty `if` block. I've also seen the opposite - an empty `else` block. There is no rule that an `if` must be paired with an `else` - at least not in any of the programming languages I've used in the past 20 years. Empty blocks are _dead code_, remove them.

### Conditional values
Nested code blocks often return a value. When these are boolean values, there's an opportunity to condense the code block and return the condition directly.

Consider the nested code within the `isEmpty` method of a `Set` class:

```php
public function isEmpty() {
    if ($this->size === 0) {
        return true;
    } else {
        return false;
    }
}
```

While this method block is only 4 lines of code, it contains multiple sub-blocks. Even for such a small number of lines this is hard to read, making the code appear more complex than it really is.

By identifying the conditional return of raw boolean values we have the rare opportunity to completely remove the nested code by directly returning the condition.

```php
public function isEmpty() {
    return $this->size === 0;
}
```

Given the context of this aptly named method combined with a now one line block, we decreased its perceived complexity. Although this line may appear dense, it is nonetheless more readable than the original.

_**Note:** Condensing conditionals can work for more data types than raw booleans. For example, you can  return the condition as an integer with a simple type cast. However this rapidly increases the complexity. Many programmers try to combat this by using a ternary. But a ternary condenses the code without decreasing the complexity, making the code less readable. In these cases, a guard clause is a better alternative._


### Guard clauses
Nested code is often the result of logical progression. As programmers we write out each condition until we reach a level where it's _safe_ to perform the action.

While this flow may be ideal for execution, it's not ideal for reading. For each nested level the reader has to maintain a growing mental model.

Consider the following implementation of the `add` method of a `Set` class:

```php
public function add($item) {
    if ($item !== null) {
        if (!$this->contains($item)) {
            $this->items[] = $item;
        }
    }
}
```

Logically the progression: if the _item_ is not `null` and if the `Set` does not contain the _item_, then add it.

The problem is not only the perceived complexity of such a simple action, but that the primary action of this code is buried at the deepest level.

Ideally the primary action of a block of code is at the top level. We can refactor the conditional to a guard clause to unravel the nested code and expose the primary action.

A guard clause simply protects our method from exceptional paths. Although they commonly appear at the top of a code block, they can appear anywhere. We can convert any nested conditional into a guard clause by applying [De Morgan's Laws](https://en.wikipedia.org/wiki/De_Morgan%27s_laws) and relinquishing control. In code, this means we negate the conditional and introduce a `return` statement.

By applying this to the `add` method our implementation becomes:

```php
public function add($item) {
  if ($item === null || $this->contains($item)) {
      return;
  }

  $this->items[] = $item;
}
```

In doing so we have not only drawn out the primary action, but emphasized the exceptional paths for our method. It is now less complex for future readers to follow. It's also easier to test as the exceptional paths are clearly drawn out.

### Switching to if
A `switch` statement is a very verbose code structure. `switch` inherently has 4 keywords and 3 levels. It's a lot to read even if the contained blocks of code are only a few lines. While this is acceptable in certain cases, it's not in others.

There are a few cases where using `if` statements instead of a `switch` statement may produce more readable code.

- When there are just a few `case` blocks the inherent structure of the `switch` statement produces more lines than the equivalent `if` statements.
- When `case` blocks contain nested code the complexity increases and readability decreases to a critical level. Using guard clauses or adopting the practices within _Big Blocks_ can improve the code.
- When type casts or calculations are needed to coax the value into the constraints of a `switch`. This doesn't apply to languages (Swift, Go, etc) that support more complex `case` comparisons.

`switch` statements are best when a 1:1 ratio exists between `case` statements and the lines of code within their blocks. Whether these lines are assignments, `return` statements, or method invocations the readability remains nearly the same provided the ratio is roughly 1:1.

```php
switch ($command) {
    case 'action':
        startRecording();
        break;
    case 'cut':
        stopRecording();
        break;
    case 'lights':
        adjustLighting();
        break;
}
```

_**Note:** In such cases where `switch` statements are streamlined, many programmers use a map, database table, or polymorphism instead. All of which are indeed additional alternatives. Just remember every solution has trade-offs (complexity). A `switch` statement is often "good enough" for most code._

### Complex loops
Another common form of nested code are loops. Loops by nature are complex. As programmers, we're cursed to be off by one and miss incremental logic. Again, we're humans not computers. So we're unlikely to win the battle against loops. They will always challenge us. The only way to combat this complexity is readability. 

I won't get into which data structures and algorithms may help improve your code. That is much too specialized. In general though, most loops deal with accumulation or invocation. If you find your codebase contains lots of loops, see if higher order functions like `filter`/`map`/`reduce` can be used. While this may not improve readability for all readers, it will improve your individual skillset.

---

_**Want more tips?** This practice is taken from [BaseCode](https://basecodefieldguide.com) - a field guide containing 10 real-world practices to help you improve the code you write every day._