Ideas about clean if statements

If you’re reading a lot of code you may get to the point where you’d like it to be clean, so it’s easier for you to read. There’re a lot of resources about the beauty of code around and in this post I’d like to share some ideas about writing concise if statements.

Although these ideas may apply to a lot of different programming languages I chose to give examples written in Java, PHP or Python. There should be no problem to translate this into other, similar languages.

Indentation hell

A lot of years ago I read a text file describing the preferred coding style for the Linux kernel: it said that you’re screwed anyway if you need more than three levels of indentation. This stems from hackers using a screen resolution that allows a certain number of characters only. Writing code that uses a lot of nested statements causes the problem that you can’t read everything on a 80×25 terminal; wrapping lines may make things worse.

Back then the solution was to either increase the screen’s resolution or write clean code. Even today the latter is a good idea not only when writing code but maybe configuration files in general. Imagine a sysadmin in the server room with an old monitor only – he’ll thank you that you formatted the comments with a text width of 80 characters or less.

Let’s have a look at an example like the following. You’ll notice that I’ve used four levels of indentation: a for loop, an if statement, another for loop and another if statement.

for (int i = 0; i < x; i++) {
  if (i == y) {
    for (int j = 0; j < z; j++) {
      if (j == a) {
        // do something special
        // ...
      }
    }
  }
}

We can spot this pattern by looking at it’s tail: a lot of closing curly brackets. Refactoring this snippet consists of splitting the code into various functions and calling them at the right time. One solution might look like so:

public void a(final int x, final int z) {
  for (int i = 0; i < x; i++) {
    if (i == y) b(z);
  }
}
 
public void b(final int z) {
  for (int j = 0; j < z; j++) {
    if (j == a) do_something_special();
  }
}
 
public void do_something_special() {
  // do something special
  // ...
}

Now, the code is much easier to read and unit testing it will be more fun too. Don’t be afraid of adding extra functions into your program when you could write it all into one method/function. The latter is harder to maintain and rest assured that more method/function calls won’t add a serious performance penalty to your application in any way.

Inverting

It’s likely that you’ve seen a method that starts with an if statement, almost all the method’s code is inside that statement and at the end of the method you find the else block with only one statement in it, maybe some error handling code.

Instead of writing if statements that span multiple pages and contain lots and lots of code the following technique allows you to have the if statement on one line. As discussed above this avoids an unnecessary level of indentation as well.

Let’s have a look at an example: a simple method containing an if statement with another if statement which holds the real code of the method.

function doIt() {
  if (something == true) {
    if (something_else == true) {
      # do something...
      # ...
    }
  } else {
    throw new Exception();
  }
}

Simply by inverting the if statements we can write them on one line, producing the following, much cleaner code:

function doIt() {
  if (something == false) throw new Exception();
  if (something_else == false) return;
  # do something...
  # ...
}

Again, not just the statement but the whole method is easier to read. If you’re checking preconditions, this is the way to go. This also prevents the indentation hell mentioned above.

Splitting

Speaking of checks for the preconditions of certain methods, one might tend to put all checks into one single if statement. This may save you from e.g. writing code to throw an exception more than once but may result in a hard to understand if statement.

I recommend writing if statements that test only one or two conditions. Have a look at the following code which contains a giant if statement.

def method(a, b, c):
  if a <= 10 or a >= 20 or \
     b == False or \
     c == 'unknown':
    raise SomeException('Invalid arguments')
  # do something...
  # ...

We could argue that the code is pretty clean and easy to understand. True in this case, but the semantics aren’t obvious. What about introducing two more methods and raising more specific exceptions? Would result in this:

def method(a, b, c):
  if not inRange(a, 10, 20):
    raise SomeException('Argument a is out of bounds')
  if not isValid(b) or not isValid(c):
    raise SomeException('Argument b or c are invalid')
  # do something...
  # ...
 
def inRange(a, start, end):
  return a >= start and a <= end
 
def isValid(a):
  return not ( a == False or a == 'unknown' )

This may bloat your code a little bit but helps you reading the code almost like a sentence. Splitting one large if statement into smaller ones may result in sensible error messages too. And the introduction of small helper methods makes unit testing fun again.

Sorting

If you’re using the previous technique – splitting a single if statement into smaller, more concise portions – you should consider the order of the if statements. Let’s think about a simple example: in a recent post I tried finding occurrences of Friday the 13th dates by iterating over a given time span. The method looked like so:

while (/* ... */) {
    date = date.plusDays(1);
 
    if (date.getDayOfMonth() != 13) continue;
    if (date.getDayOfWeek() != DateTimeConstants.FRIDAY) continue;
 
    // ...
}

The two if statements test whether the current day is a Friday the 13th date. First checking whether the current day is the 13th day of a month speeds things up a little bit because we’ll only check whether this day happens to be a friday – the other way around would be more expensive in terms of performance.

This technique also applies when your if statements call expensive methods to test a certain condition. You may want to call the ones with the least overhead first thus reducing the time spent in your if statements.

Conclusion

In this post I presented some simple solutions that should help you writing cleaner, better code regarding if statements. Following these rules will make your code much easier to read and to maintain. Just give it a try and you’ll definitely notice the positive difference.

Sure, I haven’t given any references to real projects helping you to verify that the examples given in this post exist in real projects. I think searching in real projects for code like the above shouldn’t be much of a problem. And I’m pretty sure you’ll agree on this.