I was thinking today that when I was a mid experience level engineer I have found a couple of problems where I could finally do something very smart and use 3-state logic instead of the classic true-false
one.
I jumped in excitedly only to lose it when I realized "Wait, doesn't this make instead a good enum
?". And then I went with a good ol' enum
and all was well.
And now I am thinking again: wouldn't it make sense to replace as much as boolean flags with enums
instead (or at least used named parameters).
See this example:
jsonb_set(data, '{user, role}', {
id: 'supervisor',
title: 'Chat group supervisor',
}, false);
When you are writing this, you still remember what was the false
for the last parameter.
I give you a weak and if you are not using this jsonb_set
function frequently you will have no memory of it.
We then waste time on things that could have been very clear.
Option 1: use enum
enum JsonbSetOption {
CreateIfDoesNotExist,
ThrowErrorIfDoesNotExist
}
jsonb_set(data, '{user, role}', {
id: 'supervisor',
title: 'Chat group supervisor',
}, JsonbSetOption.ThrowErrorIfDoesNotExist);
Basically anybody will know what this will do.
Option 2: passing named parameters
jsonb_set(data, '{user, role}', {
id: 'supervisor',
title: 'Chat group supervisor',
}, { throwErrorIfDoesNotExist: true });
Option 3: split it into two functions
jsonb_set_throw_on_update_path_missing(
data,
'{user, role}',
{
id: 'supervisor',
title: 'Chat group supervisor',
}
);
It is up to you whichever you choose. Please don't just use random flags or else...
receiveSalary(you, false, true, true, false, null);
Top comments (6)
I agree, and I would take it a step further--if you're passing flags, you should ask yourself if what you really need is a separate function. Like, consider:
There are times when passing flags or enums makes sense, but usually I think this is the better option because it results in less nesting inside the function (no switches or if/thens) and a little more intuitive to read the calling code (although readability is largely subjective).
I'd definitely go for a separate function. I'd reserve enums (or possibly better, strategy objects?) for the case where there is more than option and I don't want to explode the API to N×M functions.
The strategy pattern where your flags/enums are actual representations themselves of the behaviour you want to achieve is much nicer and cleaner from a declarative standpoint.
Always keeping in mind the common sense boundary of over engineering.
The problem with saying that enums are more declarative than separate function definitions is that that's really only true if you're thinking of functions as imperatives, but functions themselves are also values and can be used just as declaratively as enums, but using functions over enums better encapsulates meaning by tying the representation with the definition.
OO patterns like that are mostly an attempt to make imperative languages a little bit less imperative, but they aren't inherently better than just doing things in a functional way.
much sorry I was in a hurry I meant to type:
"where your flags/enums are functions and actual representations themselves of the behaviour"
:D
Fun fact this example was taken straight out of Postgres and indeed the flag is there, I did not make it up.
Your function names are very short and descriptive, I like them a lot! Thanks for your comment!