Pretty code: Skeptical of elses

Pretty code is readable code. One strategy for code beautification is to look critically at every if/else statement. Is there a more streamlined way to write that statement? Cultivate a general mistrust of elses.

Some examples...

Testing a boolean to return a boolean

if (x == true)
{
  return true;
}
else
{
  return false;
}

becomes

return x;

If you need to swap those,

return !x;


That's a pattern. Recall that comparison operators (less than, greater than, equal to) return a boolean. So this also applies here:

if (myPropertyToCheck == someValue)
{
  return true;
}
else
{
  return false;
}

becomes

return myPropertyToCheck == someValue;


Guard clauses
You can use a guard clause when you are testing if it is safe to do something, and if not, you want to exit.

if (safeToDoThis)
{
  DoThis();
}
else
{
  return;
}

becomes

if (!safeToDoThis) return;
DoThis();

When the DoThis() is rather involved, guard clauses greatly help the readability for your future teammates (even when that's you). Step 1, check if we're in an okay state, and if not, just get out of there. This saves you from the Hunt The Else game (although, if that matching else is that hard to find, you could break up your method into smaller pieces with more specific responsibilities).

Comparisons
Compare() and CompareTo() methods need to return -1, 1, or 0. It's handy that these are integers, because now you can harness the Power of Arithmetic to do your bidding. Also when you are comparing your own classes, you often want to compare a property that is a value type or a string. Those already have their own CompareTo() methods, which you can borrow.

Say you want to sort your children by their ages. You don't need

if (child1.age < child2.age)
{
  return -1;
}
else if...

(Not just an if/else, but an if/elseif/else. Aaah!) Use instead:

return child1.Age.CompareTo(child2.Age);

If you want to sort them from oldest to youngest, this is where the arithmetic comes in. To flip a negative 1 into a 1, multiply it by negative 1. Same for flipping positive 1 into a negative 1. And zero, conveniently, doesn't mind being multiplied by anything. So you could say:

return -1 * child1.Age.CompareTo(child2.Age);

You can get it even simpler. Because -(-1) = 1, and -(1) = -1, your Compare() method becomes:

return -child1.Age.CompareTo(child2.Age);

Not only no elses, but also no ifs! Very pretty.

Reducing the number of paths through your code (i.e., reducing cyclomatic complexity) gets it closer to being read like prose. Simpler code has fewer bugs, and your successors who have to read your code will think you are smart and good looking. Keep a healthy mistrust of else statements, and write pretty code.

5 comments:

Anonymous said...

Great post. I completely agree that removing logic in these three cases makes your code more readable, which is a good thing.

I've been surprised how much more readable my code became when I started using guard clauses.

In your last example, you ended up with:
     return -child1.Age.CompareTo(child2.Age);

Why do you prefer the mathematical form over flipping the logic:
     return child2.Age.CompareTo(child1.Age);

Sharon said...

Excellent point, Mark.

My brain went down the mathematical path because I was thinking "I want to do the opposite." Y'know, flip the sort.

I like your proposal, too, and I bet from a business-language standpoint, it is more readable. I tend to think mathy. I'll keep an eye out for this scenario and make sure I'm not obscuring my own code's readability.

Thanks for the great comment.

Rich said...

On the one hand I agree: if/then/else always makes me think in assembler... what is this making the processor do, how many cycles does this cost? (yes, I'm that old.). On the other hand, I totally disagree that your guard clause implementation increases readability--"return" and "exit" are the logical progeny of "goto." This is exactly the situation where you want an else (and the accompanying indent) to help you document and visualize the code path.

Sharon said...

I understand your aversion to goto-type syntax, Rich. I think Mr. Fowler's example on Refactoring shows the benefit better than my trivial example here.

I'm thinking of old ASP pages I've had to debug, where it starts with an if, and then - scroll-scroll-scroll - there's an else that shows an error message or some such. While you're scrolling past the if, you're kind of holding your breath, holding the thought open like a dangling left parenthesis. I feel more comfortable when the code just does a quick check, "Everything okay here?" and then gets down to business.

I've looked hard at those guard clauses though, because I had the same thought as you. "Hey... those are goto statements!" I've made my peace with them now, but I'm still interested in keeping the topic open for debate; I'm glad you raised the question. Readability and supportability are so important (on my team, they're higher priority than app performance) that it's worthwhile to keep questioning these topics.

Rich said...

Thanks, Sharon, for the assiduous follow-up and example link. I admit that my prejudice probably comes from early work in Pascal/Delphi, where returning a value doesn't imply an immediate exit. As a multi-lingual developer, keeping track of language features is a challenge, so one develops certain safeguard habits--initializing variables, Hungarian notation (yikes!), single return point--which may not be 100% optimal or agile. Guard clauses may be appropriate if they are always grouped at the top of a function and if the team agrees on the convention, but the risk of a mid-process return is always there ("there" very likely being only a place deep in my paranoia).