Why early returns make your code easier to understand
Tags: javascript, refactoring
Published: 2020-07-26 12:12:12

Quite often, I come across `if` statements starting from the very beginning of the function and stretching to the end. 

```js
function upload(file) {
  if (file.size < 9999999) {
    const directory = getStorageDirectory()
    
    /*
     * ...
     */
     
    return saveFile(directory + file.name);
  } else {
    throw new Error('File too large')
  }
}
```

The intention of these `if`-statements is clear. You want to validate the received input. However, the physical structure of the code used for this constraint is not optimal as it takes over way more area than it should be responsible for. Having to indent the whole function body because of this is a clear symptom of something being off.


Also, having the start of the structure so far away from the end of it is almost like reading a very long sentence. By the time you get to the end, you've already forgotten what was said in the beginning.


#### From this:

```js
function upload(file) {
  if (file.size < 9999999) {
    if (file.name.length > 5) { 
      if (file.format === 'jpeg') {
        saveFile('jpegs/' + file.name);
      } else {
        saveFile('others/' + file.name);
      }
    }
  }
}
```

#### To this:

```js
function upload(file) {
  if (file.size >= 9999999) {
    return;
  }
  
  if (file.name.length <= 5) {
    return;
  }

  if (file.format === 'jpeg') {
    saveFile('jpegs/' + file.name);
    return;
  }
  
  saveFile('others/' + file.name);
}
```

------------
## Explanation

**1. Always avoid nesting `if` statements**

In most cases, it's not needed. Often it's a sign that conditions should be either **flipped** (take a look at what happens to `if (file.size < 9999999)`) or **combined**.   

**1.1. Define parameter boundaries early, maximise happy code**

Notice also that by doing this, we can draw a line between dangerous code, where we're unsure about the validity of our parameters and the happy code where we know the input is always valid. Happy code is easier to both read and write, and we aim to maximise the amount of it. 

**1.2. Validate as soon as you can**

In this example, we would ideally want to validate the `file` parameter before it hits this function. That way we could drop the `if` statements altogether. We could do this, for example, in the function calling this function. Or even the function calling that one. Ideally, we wouldn't have invalid files in our application at all! 

👍 **As a rule of thumb:** 
Validate user-inputted parameters as soon as they reach your code. 


```diff
function upload(file) {
-   if (file.size < 9999999) {
-     /* 1. */
-     if (file.name.length > 5) { 
-       if (file.format === 'jpeg') {
-         saveFile('jpegs/' + file.name);
-       /* 2. */
-       } else {
-         saveFile('others/' + file.name);
-       }
-     }
+   if (file.size >= 9999999) {
+     return;
+   }
+   
+   if (file.name.length <= 5) { 
+     return
+   }
+   if (file.format === 'jpeg') {
+     saveFile('jpegs/' + file.name);
+   /* 2. */
+   } else {
+     saveFile('others/' + file.name);
  }
}
```

```js
function upload(file) {
  if (file.size >= 9999999) {
    return;
  }
  
  if (file.name.length <= 5) { 
    return
  }
  if (file.format === 'jpeg') {
    saveFile('jpegs/' + file.name);
  /* 2. */
  } else {
    saveFile('others/' + file.name);
  }
}
```

**2. `else` is often unnecessary**

In this case, getting rid of `else` by returning from the first branch gets rid of 1 level of indentation. Some linters also complain about this, because the code will be unreachable.


```diff
function upload(file) {
  if (file.size >= 9999999) {
    return;
  }
  
  if (file.name.length <= 5) { 
    return
  }
  
  if (file.format === 'jpeg') {
    saveFile('jpegs/' + file.name);
- } else {
-   saveFile('others/' + file.name);
+   return;
  }
+   
+  saveFile('others/' + file.name);
}
```

Why I say it's _often_ unnecessary is that there are cases where it can be argued using `else` improves readability. 

Consider:

```js
if (user) {
  res.send(200)
} else {
  res.send(404)
}
```

vs

```js
if (user) {
  res.send(200)
  return
} 
res.send(404)
```

Which one do you prefer? The latter one indeed saves you one indent but adds a return statement that only has the purpose of stopping the function from running.