Guard Clauses vs. Nested Conditionals

Guard Clauses vs. Nested Conditionals

An explanation of Ruby guard clauses how to use them as an alternative to nested if statements

TLDR; a guard clause is a premature return (early exit) that "guards" against the rest of your code from executing if it's not necessary (based on criteria you specify).

Soon after I started my career as a Ruby on Rails developer I learned about guard clauses and how they can improve code readability.

Let's take a look at an example method with a standard if/else statement.

def example_method(parameter)
  if parameter == true
    # awesome code here
  else
    return nil
  end
end

In this method we're doing something that's common: evaluating a parameter and:

  • executing some code if our expectations are met OR
  • executing some other code if our expectations are not met.

In this case:

  • if the parameter is true we execute some "awesome code"
  • if not, we just return nil

This method can be shortened to only two lines of code by using a guard clause.

def example_method(parameter)
  return nil unless parameter == true #<-- guard clause
  # awesome code here
end

unless method

This was as short example to illustrate the concept of a guard clause. Now let's look at an example where a guard clause can help eliminate a code smell: nested conditionals.

def print_shipping_label(order)
  if order.outstanding_payments?
    nil
  else
    if order.address_incomplete?
      order.send_address_reminder
    else
      if order.standard_shipping?
        order.print_standard_shipping_label
      else
        order.print_priority_shipping_lable
      end
    end
  end
end

This code is hard to read and follow what's happening in my opinion (just look at how many levels of indention are in the nested if/else statements!)

Refactoring Nested Conditionals Using Guard Clauses

We can use guard clauses to refactor the nested if/else statements and make the method more readable and easier to follow.

def print_shipping_label2(order)
  return nil if order.outstanding_payments?
  return order.send_address_reminder if order.address_incomplete?
  return order.print_standard_shipping_label if order.standard_shipping?
  order.print_priority_shipping_label
end

I like guard clauses for these reasons, but you should use them where it makes sense for you and your team.

For example, some languages require explicit resource management and having a single exit point from a method would make sense to prevent memory leaks. However Ruby has garbge collection to automatically collect unused objects.


Takeaway:

Guard clauses guard (protect) the rest of your code from executing if not necessary (based on certain criteria) and are placed at the top of a method.

Resources:

  1. Refactoring.com - Replace Nested Conditional with Guard Clauses

  2. Refactoring.guru - Replace Nested Conditional with Guard Clauses