Saturday, March 12, 2011

Proportionality of incremental changes

A few weeks ago I was watching a presentation on Project Lambda. The proposed syntax is generally quite nice. It's very simple, and avoids a lot of the noise which pollutes typical Java programs using inner classes. But one of the syntax examples didn't sit right with me, and it took me a few days to figure out exactly why.

The particular example isn't important, and I don't think it's currently in the public proposal. But what is important, I realized, is that code should be written to facilitate incremental changes, and this interfered with that.

What do I mean?

Here's an example: one of the rules in our coding guidelines is that control blocks must always use curly brackets. That is, don't write code like this:

if (condition)
  doSomething();
else
  doSomethingElse();

We require that this code be written like this, instead:


if (condition) {
  doSomething();
} else {
  doSomethingElse();
}

Here's why I don't like the syntax without the curly brackets (at least one of the reasons): it makes it harder to modify the code.

If you want to add an extra line inside the else block, you need to add the line and convert the single statement block into a compound block:


if (condition)
  doSomething();
else {
  fprintf(stderr, "Debugging doSomethingElse\n");
  doSomethingElse();
}

To add one line of code I need to modify three lines! This is a disproportionate amount of work considering the actual change.

In summary, code should be written in a way which encourages incremental changes. If small logical changes require large textual changes, then there's something wrong, either with the tools or the technique.

3 comments:

  1. I agree completely, Peter. Things get even worse when the one line is another control structure, such as an if-statement that has an else-clause and braces are not used again. Boy can that get confusing! You should be able to understand the code independent of white-space and indentation, which is not always the case when braces are not used. Of course for every rule there's an exception: I skip the braces when the one line is terminating, such as a return, continue break or throws.

    ReplyDelete
  2. Simon:

    No exceptions (to this rule) in our coding standards. Return, continue, break and throw must also be be in braces in this case. What if you want to change the return statement?

    Start with:

    if (foo)
    return getResult();

    and change it to:

    if (foo) {
    int result = getResult();
    return result;
    }

    Now you need the braces.

    Also, we discourage, but don't forbid returning from the middle of a function. It's essentially equivalent to a goto. I'll write more about multiple return points some other time.

    ReplyDelete
  3. I totally agree. I used to always use braces and always had "one way in, and one way out" of a method. But in recent years I've softened.

    On the braces front I cannot argue that it's better to always use them. But on the "one way out" front I must say that I find "early returns" to be helpful in simplifying the code. But I generally only do this at the start of method, rather than in the middle of a loop, for example.

    This, I guess is one of those age old arguments that software developers love to debate. So what color are we going to paint this bike shed, anyway? :-)

    ReplyDelete