rc3.org

Strong opinions, weakly held

My rules of thumb for developers: use less indentation

Over a month later, post number two in my “rules of thumb” for developers series. The first post was on writing less code, period. This one is on using less indentation.

What I really mean by this is that I’m strongly not in favor of complex nested code structures. I find them to be difficult to follow when reading code, and to be good places for little logic bugs to hide. How often have you seen code that looks like this?

if (something > 10) {
    if (something < 100) {
        // Do something
    }
    else if (something > 150) {
        // Do something else
    else {
        return false;
    }
}
else {
    while (something < 10) {
        // Do some other stuff
    }
}

I often see conditional structures three or four levels deep, comprising case statements, if statements, and loops of various kinds, and in those cases, it can be very difficult to figure out exactly which conditions have to be in place for a given line of code to be executed.

Let’s look at a really common sort of coding problem:

private boolean doSomeStuff(String str) {
    if (str.equals("something")) {
        // Perform some tasks.
        if (str.length() == 10) {
            return true;
        }
        else {
            return false;
        }
    }
    else {
        return false;
    }
}

I would always write that method like this:

private boolean doSomeStuff(String str) {
    if (!str.equals("something)) {
        return false;
    }

    // Perform some tasks.

    return str.length();
}

Any time there’s a condition that causes code to be skipped, I like to put the return statement above the code that could be skipped. It enables me to avoid a level of indentation and, I think, makes the code more readable. This approach goes hand in hand with the practice I’m going to discuss next, which is to write more methods. I think it’s always better to be able to quickly figure out which code you can ignore when you’re reading through code and trying to figure out why something is happening. In the second version of the method above, it’s easy to see the conditions under which you can ignore most of the code in the method.

It’s particularly important to avoid excess nesting when you’re talking about mixing markup with code, in PHP files, JSPs, ERB templates, or whatever. Excessive nesting can render the source nearly unreadable. It’s almost always better to use includes or other approaches to make it easy to distinguish between the control structures in the page and the markup used to render the page.

This practice may seem pretty obvious, but I don’t think I’ve ever seen it explicitly describe before, and I read a lot of code that includes lots of deeply nested structures. I’d love to hear in comments whether people see any downsides to this approach, because I’m methodist when it comes to writing code this way.

6 Comments

  1. In loops, you would use ‘break’ and ‘continue’ to achieve a similar de-nesting. ‘Continue’ is especially underused.

  2. I normally use a default return value at the end of a code function, so I’d do like(in a pseudocode):

    func f(string s){
       if(s == "something"){
        //Do something
          if( s.strlen() == 10){
        return true;
     }
      }
      return false;
    }
    

    In C I see people who like goto to do cleanup like:

    int f(char *s){
      int retv = 0;
      if(strcmp(s,"something") != 0){
        goto f_end;
      }
      //Do something
      if(strlen(s) == 10){
        retv =1;
      }
    f_end:
      //Logging, debugging messages, etc.
      return retv;
    }
    
  3. Yeah, I use continue a lot.

  4. You’re describing what is elsewhere known as a “guard clause”. It’s a fine way to handle all of the “early out” test that would otherwise clutter up a method with extra nesting.

  5. I am just chiming in with my agreement.

    Some support for this style is offered by Steve McConnell in Code Complete. Section 17.1 talks about return statements, and a key point is “Use a return when it enhances readability”.

    The downside McConnell identifies is that it can be hard to identify where a function exits if there are too many returns, but that’s an issue that is avoided more by following other principles of good style.

  6. “elsif,” “else if” and their ilk are enemies of readable code. Also, as McConnell states in CC, long functions are enemies of readability.

    A few comments go a long way

    if (something > 10) {
      if (something < 100) {
        // Do something
      } else {
        if (something > 150) {
          // Do something else
        } else {
          return false;
        } // > 150
      } // < 100
    } else {
      while (something < 10) {
        // Do some other stuff
      }
    } // > 10
    

Leave a Reply

Your email address will not be published.

*

© 2024 rc3.org

Theme by Anders NorenUp ↑