Also known as

Refactoring Replace Nested Conditional with Guard Clauses

Problem

You have a group of nested conditionals and it is hard to determine the normal flow of code execution.

Solution

Isolate all special checks and edge cases into separate clauses and place them before the main checks. Ideally, you should have a "flat" list of conditionals, one after the other.
Before
public double getPayAmount() {
  double result;
  if (isDead){
    result = deadAmount();
  }
  else {
    if (isSeparated){
      result = separatedAmount();
    }
    else {
      if (isRetired){
        result = retiredAmount();
      }
      else{
        result = normalPayAmount();
      }
    }
  }
  return result;
}
After
public double getPayAmount() {
  if (isDead){
    return deadAmount();
  }
  if (isSeparated){
    return separatedAmount();
  }
  if (isRetired){
    return retiredAmount();
  }
  return normalPayAmount();
}
Before
public double GetPayAmount()
{
  double result;
  
  if (isDead)
  {
    result = DeadAmount();
  }
  else 
  {
    if (isSeparated)
    {
      result = SeparatedAmount();
    }
    else 
    {
      if (isRetired)
      {
        result = RetiredAmount();
      }
      else
      {
        result = NormalPayAmount();
      }
    }
  }
  
  return result;
}
After
public double GetPayAmount() 
{
  if (isDead)
  {
    return DeadAmount();
  }
  if (isSeparated)
  {
    return SeparatedAmount();
  }
  if (isRetired)
  {
    return RetiredAmount();
  }
  return NormalPayAmount();
}
Before
public function getPayAmount() {
  if ($this->isDead)
    $result = $this->deadAmount();
  else {
    if ($this->isSeparated)
      $result = $this->separatedAmount();
    else {
      if ($this->isRetired)
        $result = $this->retiredAmount();
      else
        $result = $this->normalPayAmount();
    }
  }
  return $result;
}
After
public function getPayAmount() {
  if ($this->isDead)
    return $this->deadAmount();
  if ($this->isSeparated)
    return $this->separatedAmount();
  if ($this->isRetired)
    return $this->retiredAmount();
  return $this->normalPayAmount();
}
Before
def getPayAmount(self):
    if self.isDead:
        result = deadAmount()
    else:
        if self.isSeparated:
            result = separatedAmount()
        else:
            if self.isRetired:
                result = retiredAmount()
            else:
                result = normalPayAmount()
    return result
After
def getPayAmount(self):
    if self.isDead:
        return deadAmount()
    if self.isSeparated:
        return separatedAmount()
    if self.isRetired:
        return retiredAmount()
    return normalPayAmount()

Why Refactor

Spotting the "conditional from hell" is fairly easy. The indentations of each level of nestedness form an arrow, pointing to the right in the direction of pain and woe:

if () {
    if () {
        do {
            if () {
                if () {
                    if () {
                        ...
                    }
                }
                ...
            }
            ...
        }
        while ();
        ...
    }
    else {
        ...
    }
}

It is difficult to figure out what each conditional does and how, since the "normal" flow of code execution is not immediately obvious. These conditionals indicate helter-skelter evolution, with each condition added as a stopgap measure without any thought paid to optimizing the overall structure.

To simplify the situation, isolate the special cases into separate conditions that immediately end execution and return a null value if the guard clauses are true. In effect, your mission here is to make the structure flat.

How to Refactor

Try to rid the code of side effects – Separate Query from Modifier may be helpful for the purpose. This solution will be necessary for the reshuffling described below.

  1. Isolate all guard clauses that lead to calling an exception or immediate return of a value from the method. Place these conditions at the beginning of the method.

  2. After rearrangement is complete and all tests are successfully completed, see whether you can use Consolidate Conditional Expression for guard clauses that lead to the same exceptions or returned values.

Tired of reading?

No wonder, there are 7 hours worth of the text on this website.

Try out something different. We've just launched the interactive learning course on refactoring. It has more content and much more fun than a boring text.

Learn more...

Live Example

First time here? No worries!

Everything is quite simple. This example is like video (but much cooler):

  1. After pressing the Play button, you will see floating messages, which will guide you through the example. You can proceed by clicking on them.
  2. You can fast-forward or return to previous steps by pressing arrow buttons on the left.
  3. Also, you can take a look at the code diff window, which will show what has changed in code during the example ()
  4. To check the code for errors, you can press "Compile and test" button ()