I am sick and tired of “X is a code smell” articles. Everything in software development <i>depends</i> on context. What makes perfect sense in context A makes zero sense in context B. If (for example) all you know is front-end JavaScript development then don’t make claims about anything outside of that context. Have you ever only worked in one industry? Then perhaps realise that your experience might be limited to that context. While being completely and utterly wrong in a different context. I have worked in <i>many</i> different contexts in my 25+ years career. AAA game development, high-performance compilers, low-powered embedded systems, typescript/react front-end development, enterprise software applications, mobile apps etc. And the #1 thing I have learned is that <i>nothing</i> is true or false in all contexts. <i>Everything</i> depends on your particular situation and context. So be aware of your limited context and perhaps think about what would no longer be true/false when you change the context.
Flags are not code smells and this article doesn't convince me otherwise. It's basically saying that they can be misused. Okay. <i>Everything</i> (from inheritance, to polymorphism, to functional programming) can be misused, so that's not really an argument against flags themselves. Flags & bitmasks (pun intended) are probably some of the most long-lived patterns in software engineering, so the argument would have to be particularly compelling, which it isn't.
A more specific (and so hopefully less arbitrary) claim for you all:<p>In CRUD apps, database tables with lots of boolean columns are a data-architecture smell.<p>In my experience, the model encoded by such a record is almost always a — perhaps implicit — finite state machine of some kind. Usually, in CRUD stuff, this is a "lifecycle state" machine. (For example, the BlogComment lifecycle: draft → awaiting moderation → visible → deleted.)<p>But, because the people who create and evolve data schemas aren't usually familiar with FSMs, there's often no explicit "lifecycle state" enum-typed column in the DB record.<p>Instead, you get this pile of boolean columns, where each column represents the <i>answer to a predicate</i> that would take the model's lifecycle state as its input. Think e.g. `can_login?(User)` — which really just boils down to `can_login?(UserLifecycleState)`.<p>If you add the lifecycle-state column, then all the predicate-answer columns can go away. As long as you formally define+document the meaning of each lifecycle state, you can then statelessly recompute all those predicate-answers any time you like, on any layer of the stack you like. And now those predicate-answers will never be able to end up in an <i>incoherent</i> state, because they're never persisted; only the lifecycle-state itself is.<p>Of course, if you actually go all the way and make your model an FSM on the business layer as well, then you'll <i>also</i> get as a free benefit, the ability to validate lifecycle-state transitions — e.g. "Articles should only be able to enter the Published state from the Reviewed state."
I'm becoming convinced that using the phrase "code smell" might as well be a "smell" itself. Maybe it's just me, but I've only heard the phrase used as a rhetorical mask for a developer to express some individual preference as though it were an objective fact.
One of the things I disliked the most about software development was when somebody wrote an article like this, and then somebody on my team would be like "see? you can't use flags, it's a code smell. There's an article about it, and it got on Hackernews and everything. We don't want our code to smell. Flags considered harmful. Will not approve any PRs with flags!"<p>Article Driven Development. People are allowed to have their opinions, but sheesh. Just say "here is a problem you can run into with flags, better be careful!"
The article's most interesting point is that the vast majority of possible program (or object) states tend to be invalid. For example, `Person(isWalking=true, isAlive=false)` is nonsense, because there's an unexpressed constraint that `isWalking==true ==> isAlive==true`.<p>Though the author veers in another direction, I think his core point is related to this discussion:<p>Applying “make invalid states unrepresentable”
<a href="https://news.ycombinator.com/item?id=24685772" rel="nofollow">https://news.ycombinator.com/item?id=24685772</a>
Nope. Not at all. For example, a friend of mine is working on an enterprise system used by a number of very large international companies. Every company demands slight variations to everything. From UI look/flow to how low level business logic is done. Flags are <i>perfect</i> for this. The key of course is to make sure that the flags are used correctly. By (for example) having a validation step at startup making sure the flags are configured correctly. Or (even better) using types to make it impossible to configure it incorrectly.
If you find yourself passing in flags to change behavior, it sounds like you should just have two functions. For other cases, an enum might serve your needs better as it gives you more options as your codebase grows. That said, I wouldn't call boolean flags a _smell_. Seems like throwing out the baby with the bath water if you ask me.
> Ok, so far we have three flags which means we have 23 = 8 possible combinations of flags, but do we really have eight separate legal states? No!<p>It’s a good argument for a custom sum type in place of the booleans.
Flags are a universally understood programming idiom. It is not the best way, but it is well-understood. And that counts for a lot in programming practice.
Creating many boolean states leads to an explosion of complexity and states. You can use a finite state machine to replace these states as I wrote here: <a href="https://www.lloydatkinson.net/posts/2022/modelling-workflows-with-finite-state-machines-in-dotnet/" rel="nofollow">https://www.lloydatkinson.net/posts/2022/modelling-workflows...</a>
I notice that these code smells as discussed are often really a function of the domain the developer is in.<p>Lots of game examples, saw some sql too.<p>What for me is the main reason not to like flags/booleans, is the current hype of MVP.<p>Yeah, sure, a decision cam be yes or no for the current process. But what about, yes, but.... or no, unless.... for later iterations?<p>Also, focussing on current user requirements leads to many booleans. What about, when the process is optimal, is it still a yes/no question?<p>I also notice questions on different levels. In case of visible and static, for instance. One has to do (i guess) with rendering behaviour, while the other has to do with (let me call it) game engine behaviour.<p>Is it then maybe also a case of (re-)defining the data models, as the element you're trying to specify gains depth?<p>Even, possibly, that your definitions have become convoluted? In the game example, a difference between the element as an actor in a game scene as opposed to its representation for a render engine?
Most of the individual boolean flags in the code I work with are retrieved on-demand from a feature-flag store. Well, aside from the dryRun flag that a lot of utility things take.<p>But this actually seems to be talking about having <i>object state</i> represented internally as a pile of flags when something more semantically meaningful is available.
I'm not sure I agree with this article. I have been looking at the source code of some open source games and they all make use of a mix of flags and some sort of polymorphism. At some level, when you get into a low enough level class, there is most certainly a ton of if, else, and flags. Not everything can be normalized elegantly into polymorphism, because there are too many combinations.<p>I wouldn't describe these open source games as having code smell, but rather just being very complex. Using flags seems to be a very effective way of encapsulating the complexity.<p>I have not looked at a popular open source game that has really used the approach described in the article. Does anyone have any references for that?
I don’t like using them, but, sometimes, they are required.<p>That pretty much sums up all kinds of “smelly” practices.<p>In my experience, “God said it, I believe it, and that settles it” type pronouncements end up looking fairly silly. We do what needs doing, to achieve our ends.<p>At least, that’s what most experienced ship programmers do.<p>What I prefer (I program in Swift), are computed properties that examine the current state, and synthesize a report on demand.<p>Can’t always do that, though. Things like performance and threading can be factors. I just ran into something like that, tonight. Not sure how I’ll solve it. I’ll sleep on it.
flags are fine. If they reduce complexity.
Is it easier to add a comment about what the flags do for the next dev than describe the other structures to avoid the flags?
You won't the last dev to touch that code. Write the simplest thing possible.
A bit hyperbolic calling code smell. They even mention they have their uses.<p>I think the main point of this post is be careful with state explosion since each flag grows the number of states exponentially and likely not all of then are legal or make sense.<p>The other point is grouping similar things in memory is good for performance. Less failed branch predictions from checking flags and better cache coherence.<p>Thats not as a click bite-y of a title though.<p>Although the above is sound advice.
Shit. I guess I should remove the flags from my models.<p>But now how do I tell if a company is a qualified vendor or not? If a user is active and can login.<p>I could have sworn I just read an article about putting code that's not ready behind a feature flag instead of long running git branches... guess that was a fever dream?
Article about nothing. Take feature A and declare it code smell and the say that in many cases it is actually not. In programming any single feature / concept is like that. Good for one case, bad for the other.