Why Coding Without If-Statements Can Help Make Better Code

In the office the other day, we were talking about this good tip about coding without if-statements by Samer Buna. Samer suggests that from time to time, you take a bit of your code and re-write it without using conditional statements. The idea is that you learn other ways to structure your code. You become comfortable with data-driven and/or object oriented solutions to problems.

Samer doesn’t suggest that you should never use an if statement, and I wouldn’t either. I do think being careful with conditional logic makes better code. The rest of this post covers two approaches for using conditionals responsibly.

Consider separating your code into two kinds of methods or functions:

  • Ones that contain conditionals and calls to other methods (but nothing else)
  • Ones that do the work (but don’t contain conditionals)

Here’s a method that doesn’t follow that approach:

function updateOrInitializeOrder(order, updates) {
  if(order == null) {  
    order = new Order();
    order.subtotal = updates.subtotal || 0;
    order.items = updates.items || [];
    // etc
  } else {
    order.subtotal = updates.subtotal || order.subtotal;
    // etc
  }
}

I would do:

function updateOrInitializeOrder(order, updates) {
  if(order == null) {
    return initializeOrder(updates)
  } else {
    return updateOrder(order, updates)
  }
 }
 
function initializeOrder(updates) {
  // …etc
}
 
function updateOrder(order, updates) {
  // …etc
}

To me, this makes the code easier to read because the updateOrInitializeOrder method (with conditionals) is an overview of what happens in each situation. So long as your method names are accurate, you know at a glance what is happening. In the original version, you have to “mentally compile” and step through the code in your head. This is slower and more error-prone.

The second method is “flattening” conditionals. Take code that contains varying levels of nested conditionals and make it at most one level deep. Here’s some code with mixed levels of conditional nesting:

if (a) {
  if(b) {
    foo();
  }
  bar();
} else {
  baz();
  if(c) {
    qux();
  }
}
qaz();

The nesting changes willy-nilly. It is difficult to track which conditionals apply to which lines.

Instead, unroll your boolean logic. Find a version that means the same thing and is only one level deep:

if (a && b) {
  foo();
  bar();
  qaz();
} else if(a) {
  bar();
  qaz();
} else if(c) {
  baz();
  quz();
  qaz();
} else {
  baz();
  qaz();
}

This is more lines of code, and it does contain some repetition, but you can easily determine what happens in which case. Find the relevant conditional. Look at the code between the brackets. That’s it. For best effect, use this second technique with the first, and turn the body of each conditional into a descriptively named method.

You can take these techniques too far. Applied reasonably, coding without if-statements can make your code better. And compared to data-driven approaches, you can more easily measure test coverage and profile performance. They also make full-text search of your code effective (i.e. “passes the grep test”).

We love making great software – Let’s work together.

Apply to work with us  or Hire us to round out your tech team!

Check out more of our thoughts on development and product.