Ruby guard clauses - how you can refactor conditional logic

ryanwhocodes
ryanwhocodes
Aug 5, 2018 · 3 min read

Learn the syntax of guard clauses in Ruby and how to use them to refactor your code.

This short refactoring tutorial will explain how you can write guard clauses for your if statements, rather than using nested if .. else conditional logic. This can help you to create clean and easy to read code. It will give examples using Ruby, but the same programming style can apply to other languages.

Avoid nested if .. else logic

What may start off as one set of conditions managed by an if .. else block can easily become difficult to understand when more and more if .. else logic is added to manage various conditions.

def admin?(user)
 if (user.role == 'admin')
  if (user.manager == true)
    return true;
  else
    return false;
  end
 else
  return false;
 end
end

This can result in code in which it is challenging for developers to follow the flow of logic. It can also be time consuming to maintain or amend code later on. An alternative programming style is to use guard clauses, which achieve the same outcomes but can be easier to read.

The guard clause

This structure guards the flow of logic from continuing if certain conditions are met, or not met.

return ACTION if CONDITION

Guard clauses can reduce the number of lines in your functions, classes, and so on. A result of using multiple guard clauses is that you can see what conditions trigger certain code to be executed.

return false if user.role != 'admin'

Here is the above example refactored using guard clauses.

def admin?(user)
 return false if (user.role != 'admin')
 return false if (user.manager != true)
 true
end

Note how the number of lines of code has reduced from 13 to 5!

Further refactoring using code extractions

A further way to develop this refactoring strategy is to extract code to other functions, classes, or modules, which are then called within guard clauses. It means you can use more complex conditional logic for an if statement within a guard clause. Here is a simple example of code extracted to separate functions.

def has_admin_role?(user)
 user.role == 'admin'
end

def is_senior_manager?(user)
 user.manager == 'senior'
end

Now you have extracted key logic, you can unit test these independently from the original code. This can help you to identify, isolate, and iron out bugs within a large code base.

Here are the extracted functions applied to the original example.

def admin?(user)
 return true if (has_admin_role?(user) && is_senior_manager?(user))
 false
end

It can even be refactored down to 3 lines for the original method.

def admin?(user)
 has_admin_role?(user) && is_senior_manager?(user)
end

En conclusion!

Applying this strategy to a complex code block can help you gain control of your code logic in way that makes code maintainable and scalable. Refactoring is an art form, and there are always ways to keep refining this skill as a developer.

Header original image source: inspiremusic.com/en-garde