At $JOB, we have feature flags of innumerable shapes and sizes. Some are based on account standing, some are % gradual rollout at random, others are a more thoughtful low-risk to high-risk rollout across customers and hosts. Some are manual flipped per customer/only on certain dev hosts. Literally anything you can think of, we have tied behavior to it.
But, we've got good frameworks in place such that at the call sites where behavior diverges, it's just checking a boolean.
if PermissionController.get().get(MyPerm.class): doA() else: doB().
I suspect this is pretty common, and its still easy to do the dead code elimination on.
> if PermissionController.get().get(MyPerm.class): doA() else: doB().
oh, but if a behavior changes when a feature flag is active, there's a very strong case for it to be pluggable behavior strategy, so I like these so much better as an unconditional call to `self.getThingStrategy().execute()`
Yes, but you move the logic for deciding which branch to take to an underlying function. It pollutes the parent function less, but results in more overall functions for places to hide.
Also, if the logic gets more complicated than just an if statement (if Permision... and date < cutoffdate: etc) you don't further pollute the parent function.
Naah, but at least that would make the decision simple and clear (if condition return doA else return doB).
Better would be for whatever ThingFactory or getThingService instantiates the Thing to make the decision, and compute it up front.
If-else statements in application logic tangle the concepts of "what should be done and why?" with "let me do this Way 1" and "let me do this Way 2". Ideally a typical service (or model or similar) shouldn't be aware that "feature flags" as a concept exist, and this should be regarded as inimical to their encapsulation. It should just know that it delegates a decision to Way N.
But, we've got good frameworks in place such that at the call sites where behavior diverges, it's just checking a boolean.
if PermissionController.get().get(MyPerm.class): doA() else: doB().
I suspect this is pretty common, and its still easy to do the dead code elimination on.