Refactoring Ruby: Introduce Null Object
Introduce Null Object is a great refactoring tool when you find yourself checking for nil
too often. nil
checks are often signs of much larger problems, as it violates Tell, Don’t Ask, and results in defensive, bug prone programming. Let’s take a look at a simple example of refactoring nil
checks:
This Movie
class is incredibly defensive, it goes to great lengths to ensure its account
actually exists. Why should that responsibility fall on Movie
? It would be much better for Movie
to just assume it has an account OR something resembling an account. Let’s Introduce Null Object:
We have gotten rid of all conditions defending against nil
and introduced one that always returns an Account
like object:
def account
@account ||= NullAccount.new
end
Let’s run through the exact steps to take when applying Introduce Null Object:
- Identify conditions that check for
nil
, that are defending against objects potentially not existing, for example:
def rent
# nil check
unless account.nil?
account.charge(@price)
end
end
2. Create an object that acts like the one you are checking for as nil
. Specifically, create a new class and define all of the methods that are expected to be there, for example:
class NullAccount
def charge(_price)
"No Charge"
end
end
3. Finally, substitute the null object when the expected one does not exist, for example:
Class Movie
... def account
@account ||= NullAccount.new
end
end
Null objects are great at replacing conditional logic and making code more readable, as you don’t have to think through all of the different branches conditions introduce.