Ever seen a hard-to-parse conditional like this?
def allow_access_to_site?
! (signed_out? && untrusted_ip?)
end
Let’s use De Morgan’s Laws to clean it up and see who actually has access to our site.
De Morgan’s Laws
Whoa, who’s this De Morgan guy? Augustus De Morgan, in addition to looking like a 19th-century John C. Reilly, formulated two important rules of logical inference. You can check out the formal definition on the Wikipedia page, but here they are in Ruby code:
# First law
!(a && b) == !a || !b
# Second law
!(a || b) == !a && !b
Well hey, it looks like we can use these on our gnarly conditional above. Let’s try it.
Law-abiding Ruby code
Recall that the original conditional was ! (signed_out? && untrusted_ip?)
.
Let’s use the first law and puzzle it out.
# Original
! (signed_out? && untrusted_ip?)
# Conversion using first law. I've added parentheses for clarity.
# a = signed_out?
# b = untrusted_ip?
(! signed_out?) || (! untrusted_ip?)
Here I notice that ! signed_out?
and ! untrusted_ip?
are double negatives:
not signed out, not untrusted IP. Now what they’re really trying to say
is: signed in, trusted IP. Let’s simplify further, using better method
names.
# Simplify a: (! signed_out?) == signed_in?
(signed_in?) || (! untrusted_ip?)
# Simplify b: (! untrusted_ip?) == trusted_ip?
(signed_in?) || (trusted_ip?)
# Remove parentheses
signed_in? || trusted_ip?
These methods, signed_in?
and trusted_ip?
, might exist and they might not.
Creating them is part of this refactoring. You might even end up removing the
signed_out?
and untrusted_ip?
methods in favor of these new,
positively-named methods.
And that’s it. We took a hard-to-parse conditional and made it clearer and easier-to-read using De Morgan’s first law.
Before:
def allow_access_to_site?
! (signed_out? && untrusted_ip?)
end
After:
def allow_access_to_site?
signed_in? || trusted_ip?
end
What’s next
If you found this useful, you might also enjoy: