Presence is Boolean
- 2 minutes read - 413 wordsWhen possible, I prefer to use the presence of data to represent a boolean, rather than a boolean itself.
Here’s a problematic pattern I see a lot in frontend code. Imagine we’ve made
network request that returns an error. Our code sets a boolean errorState
(“are we in an error state?”) to true
. Then we display an errorMessage
for
that condition:
if(isErrorState) {
displayMessage(errorMessage)
}
We now have two variables representing our error condition: isErrorState
and
errorMessage
. When that happens, it’s trivially easy to put the app into one of
these illogical states:
- We’re in an error state… but there’s no error message?!
- We’re not in an error state… but there’s an error message?!
Common sense says they should both either be truthy or falsy. A disagreement is problem.
Rather than creating both a boolean and a string, a pattern I prefer is to let the string’s presence be the boolean.
if(errorMessage) {
display(errorMessage)
}
An Example: App Configuration
Fertile ground for this mistake is app configuration. Consider a boolean in the
environment called SENTRY_ENABLED
and a string SENTRY_URL
. This design
makes it easy to put the app in state where Sentry is enabled, but has no URL. A
better choice is to let the presence of SENTRY_URL
tell us whether Sentry is
enabled. You can even codify this in a helper method.
def sentry_enabled?
ENV["SENTRY_URL"].present?
end
An Example: React Data Presentation
Another example is some conditional view logic that looks like this:
// template
canDisplayName() && <p>{displayName()}</p>
// functions
const canDisplayName = () => data.firstName && data.lastName
const displayName = () => `${data.firstName} ${data.lastName}`
The first function, canDisplayName
, is a little indirect. Separating the
logic that says “can this safely render?” from the rendering is redundant; both
functions “know” the same things.
Here’s a version where the presence of data becomes the boolean.
// template
displayName() && <p>{displayName()}</p>
// functions
const displayName = () => {
if(data.firstName && data.lastName)
return `${data.firstName} ${data.lastName}`
}
}
The presence of firstName
and lastName
returns a string like "Jake Worth"
or undefined
. Hence we get truthiness and falsiness and display data in one
function.
This becomes advantageous when displayName
needs to change. Instead of two or more
functions all reading the same data, there’s just one.
For further exploration, check out Matt Pocock’s State Management: How to tell a bad boolean from a good boolean. I’ll conclude with a quote from that post.
Bad booleans represent state. Good booleans are derived from state. – Matt Pocock