DEV Community

Andy Richardson
Andy Richardson

Posted on • Updated on

Going back to basics: Conditionals

If you're reading this, there's a good chance you learned how to use conditionals years ago.

If not, throw Error("learn conditionals")

Given how early on we learn about them, it's easy to overlook the impact of conditional management and how conditions can spiral out of control.

Below are a few real world examples of code I've seen in the wild and some tips on how to avoid these traps!

Avoiding reassignment

Starting off with the basics, if you're able to assign a value at declaration time, you have one less moving part in your code.

Here's a basic example where reassignment is used.

let x;

if (y > 5) {
  x = "large"
} else {
  x = "small"
}
Enter fullscreen mode Exit fullscreen mode

In the following example, we remove the need for reassignment by using a ternary.

const x = (y > 5) ? "large" : "small";
Enter fullscreen mode Exit fullscreen mode

If your language doesn't support ternaries, or you have more than two conditions to consider, you can opt for isolating your conditional logic into a function.

const x = getSize(y)
Enter fullscreen mode Exit fullscreen mode

Note: A good exception to this rule is when iterating through collections

Flattening conditionals

Another tip is to keep your conditions flat - even if this means reusing a value inside of your conditional check.

This trims down the number of conditions you need to work with.

Here's an example of nested conditionals.

if (x) {
  if (x > 5) {
    return "large"; 
  } else {
    return "small";
  }
} else {
  return "unknown";
}
Enter fullscreen mode Exit fullscreen mode

And here is an identical function body but with flattened conditionals.

if (x && x > 5) {
  return "large"
}

if (x && x < 5) {
  return "small"; 
}

if (!x) {
  return "unknown"
}
Enter fullscreen mode Exit fullscreen mode

This example segues us nicely onto this next tip...

Handling undesirable states early on

Anyone who has used JavaScript callbacks likely recognises this pattern

doSomething((err, data) => {
  if (err) {
    return handleError(err)
  }

  handleData(data);
})
Enter fullscreen mode Exit fullscreen mode

By handling undesirable states early on with a conditional guard, we add a layer of safety to all successive code and remove the need to re-check.

We can apply this pattern to our flattening conditionals example

if (!x) {
  return "unknown"
}

if (x > 5) {
  return "large";
}

return "small"; 
Enter fullscreen mode Exit fullscreen mode

Remember, the logic for this is identical to the earlier nested conditional example. Which do you think is easier to read?

Conclusion

These few tips are a solid guideline for how to break out your code and can have a substantial impact on reducing the number of moving parts and interleaving conditions.

When writing code with lots of conditional logic, remember to ask yourself

  • What are the different resulting states/actions that can occur
  • What conditions are required to meet these states
  • How can I implement them in a way that is mutually exclusive

TL;DR: Keep things static, return often, and take a moment to think about your logic.


Hopefully, you found this interesting! If you have any thoughts or comments, feel free to drop them below or hit me up on twitter - @andyrichardsonn

Disclaimer: All opinions expressed in this article are my own.

Discussion (0)