Using Guard Clauses and Conditional Logic in Ruby

Photo by Caleb Jones on Unsplash

Programming is built around the concept of conditional logic. A user sees their profile or a login screen depending on whether their login_status is true or false. While a setting like normal or dark mode is binary and straightforward, logic for different user permissions can become quite complicated as you check for many different factors. Because of this, conditional logic can grow from binary logic to ternary on up.

When you first start out programming, you are introduced to if-else blocks. While these work great for certain applications, as you develop your skills, you’ll start to see instances where a different conditional pattern is better suited for use and readability. In this article we will look at 5 different conditional logic patterns including one of my favorites, the guard clause.

If else blocks

When people think of programming, this pattern is one of the To non-programmers, the entire internet runs on an endless set of if-else assertions. For simple programs, or simplistic designs, this may be true. As you will see in this program, there are other and often times, better tools for getting logic settled.

If-else blocks operate on the idea that if a certain condition is true you do one thing, and if it’s false you do another. You can add more variety and complexity by joining more options to your logic flow through the use of else if blocks. A good example of this comes in the following figure:

Figure 1. Using if-else to feed the animals

As you can see we have multiple food items we could return based on which animal is passed into this method. It’s simple and easy to follow. A downside of this pattern is that as the list grows it gets harder to read. Notice how lacking in DRYness the condition checks are as each condition requires the repeated code of “animal == X”. If you have less four options, an if-else block works, but if you have any more you should look at using a case (switch) statement.

Case / Switch Statements

Where if-else block fails in not being DRY, case statements come in to help make your code easier to read and less repetitive. If you come from another programming language then you should know that a case statement is just Ruby’s name for a switch statement. In this pattern you are checking for the value of a single attribute and responding in a number of ways. Let’s look at the example below:

Figure 2. Using Case Statement to better feed the animals

Notice how much cleaner and less repetitive this code is. Here we know that we are returning certain logic based on the animal passed in as our argument. Each condition looks at when the animal argument is a certain value and returns the corresponding food. This is clean, easy to read and best of all DRY.

Ternary Statements

If-else and Case statements are great if you’re dealing with many conditions, but is it best if you only have a boolean expression to evaluate? This is where you want to turn to ternary statements. Ternary Statements are a great control logic tool if you are dealing with only two options. Ternary Statements evaluate an expression and return one of two values. These operators take the following structure:

Figure 3. Ternary operator to decide what you’re doing toay

Ternary Statements make use of the ternary operator and use a “expression ? true_response : false_response” flow to respond to logic. This is a clean and understandable pattern for testing if an expression is true or false. (A side note on the above example: If a method returns a boolean value, end the method name with a “?” to make it easier for other developers to readit).

Elvis Operator

When making repeated calls for non-changing variables has your program running slow, it’s time to turn to the King of Rock and Roll. Yes, you heard me correctly. A pattern that is very common for memoizing expensive variable assignments uses the Elvis operator.

The Elvis Operator is a binary operator that in C# => “ ?: ” which slightly resembles the King himself. Ruby is a little less fun with its Elvis operator opting for “ ||= ”. To better understand this operator let’s look at this figure:

Figure 4. Using the Elvis Operator to conditionally memoize variable

Here we are accessing the current user for some purpose in our code. The call to get this user is for some reason resource heavy (maybe the intern set up the method) and because of that we don’t want to call it every time we access the current_user. To get around this we use this bit of conditional logic where we see if @current_user has a value. If it does, we return its current value, otherwise we make our expensive call and save the value to @current_user

Some programmer have trouble reading the operator correctly, so the following figure shows the breakdown of how assignment occurs:

@current_user || @current_user = fetch_user_from_db

Guard Clause

The last conditional logic pattern we will look at is the guard clause. This pattern is short and to the point and is a great tool when you want to avoid costly method calls. Say you are working with a bank and writing logic to check a user’s balance. This logic requires making a call to the database and passing the user_id to get back the balance.

On its face this seems like a pretty straight forward method, but what would you do if there was no balance because the user had just signed up? Their profile exists, but there is no account tied to their profile and therefore no balance.

In this cause it would be great if there was a way to guard against unnecessary calls to the database. This is where our guard clauses come in. See the following example of our check_bank_account_balance method:

Figure 5. Guard Clause used to avoid unnecessary call to return bank statement

On the second line of code we see our guard clause where we have the option to conditionally return early. There is little computation need to check if a value is nil, but a lot of resources spent to make the call and then check what the note is for the return statement. The guard clause helps cleanup unnecessary and costly API and db calls and is a great pattern for anyone doing backend work.

Final Thoughts

I hope that you have gained a new set of tools for approaching conditional logic, or at least a better understanding of the tools you already use. Leave a comment below with your favorite conditional logic pattern or the biggest mistake you’ve found yourself making when writing conditional logic.

Notes

https://en.wikipedia.org/wiki/Elvis_operator

Former Big Beer Engineer turned Full Stack Software Engineer