DEV Community

Lucian Ghinda
Lucian Ghinda

Posted on • Originally published at notes.ghinda.com

Code Design - What would you choose?

Context

Consider a list of predicates for an object and the fact that there is a logical priority of considering them.

This is just an example, so please do not focus on the requirements themselves.

If an account is _archived_ or _closed_ then that is the final status (**Archived** 
or **Closed**) and everything else should be ignored. 
Eg: 
- An account _not verified_ and _closed_ is **Closed**
- An account _not verified_ and _archived_ is **Archived**

If an account is _active_ and _not verified_ the status should be **ActionRequired**.
Else if the account is _active_ and _verified_ the status should be **Completed**.
Enter fullscreen mode Exit fullscreen mode

Case statement vs if/else

Example of case statement and if/else implementation

Left side contains a case statement without a case condition and the right side the same logic implemented with if/else.

Which one do you prefer and why?

Case Statement vs Early Returns/Guard-like clauses

Example of case statement and guard clause implementation

Here is an alternative (right side) using guard clauses instead of if/else.

Which one do you prefer and why?

Multiple statuses

Image with code sample about multiple statuses

What if there are more statuses to take into consideration?

Which one do you prefer and why?

My preference

Somehow, for me, the case statement makes more sense when I take into consideration:

  • the order in how the conditions are assessed
  • it is a bit more open to add more statuses
  • I somehow feel a bit uneasy after using 2 guard clauses (or early returns) in a method

Top comments (2)

Collapse
 
pimp_my_ruby profile image
Pimp My Ruby

I never thought of using a case block without a case condition, thanks for this aha !

For me, I always go for guard clause / early returns in my function. As we're using Rubocop, we need to limit the size of functions.

In this context, I always ask this question -> "What if we got 20 statuses ?"
If it's highly possible, I will make an array like this :

ACCOUNT_STATUSES = [
  [:archived?, Status::Archived],
  [:closed?, Status::Closed],
  [:active_and_verified?, Status::Completed],
  # add 20 more conditions
].freeze

DEFAULT_STATUS = Status::ActionRequired

def account_status(account)
  ACCOUNT_STATUSES.each do |method, status|
    return status if account.send(method)
  end
  DEFAULT_STATUS
end
Enter fullscreen mode Exit fullscreen mode

If it's not that possible, I surely stay for early returns !

Collapse
 
lucianghinda profile image
Lucian Ghinda

I find your proposal an elegant solution to handling a lot of states and I like the approach with DEFAULT_STATUS

I do hope I will not need it :) cause that means the states graph for that account got a lot bigger so there are problably a lot of conditions to cover.