For some time now, I have been accumulating a bitterness about APIs returning optional booleans. Such disdain has been kept to myself. Until last week.
The last tweet in particular, explains, succinctly the problem: any API that returns an
Bool? puts the onus, of a default value, on the consumer.
Let's look at a trivial situation. The client receives an entity that is translated into this
From a backend perspective, the argument could be: "at this point we don't know if the user is a subscriber or not". For example, when the user signed up for the first time.
Although this might be an innocuous remark, when such entity is bubbled up to a profile screen, we, as the consumer, need to decide what to do with with it:
nilvalue by default could be considered
false. Although this is what 99% of the time one might do, this doesn't necessarily equate to the right user experience. The user, might not even know what does it mean to be a subscriber.
- A second option, is to replace the
Bool?with our own type:
One might argue that this is equivalent to a
Bool?, and from a number of possible cases, it is, but it provides far better context to whoever check the
UserProfile. The case
newUser is named as such, because after the registration, we have no idea about its subscription status.
From a UI perspective, it also makes things clear:
While most of us are also used to a boolean following the form
isSomethingEnabled, it's conceivable that an API could return
isSomethingDisabled. This means that the canonical if
false, no longer holds and one would have to make
true as the default value if
It's also quite common for a backend to have at least three consumers: iOS, Android and Web. Which means that each team will decide, what's the right default three times.
Ok, so does this mean one should never use
Bool?? Throughout the thread, a few people point out cases that have some legitimacy and its usage is warranted. Still, in each case, these could potentially be improved by either:
- Providing an enum to give more context to whoever would use such model object.
- There's a suitable default value that could be used instead of
Nonetheless, it can become unpractical to translate all
Bool? to their own enums. Not only that, the suggestions above assume we control the whole system.