Ruby guard clauses - how you can refactor conditional logic
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
- The guard clause
- Further refactoring using code extractions
- En conclusion!
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
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