A feature flag PSA

I Threaded - made a thread? Posted? Tweeted (can we use that again now)? Whatever - about this earlier but I thought I’d elaborate a little.

You do use feature flags, right?

You should. If you work with trunk-based development, like everyone does now, you must use feature flags to hide upcoming features. Side note: this is why release notes are so boring now, because features aren’t really tied to releases.

They’re not just for features! Use them to killswitch every patch you do too. Everyone eventually merges in a hotfix which makes the problem worse/creates a new problem. How nice would it be if you could just turn it off and carry on with your weekend?

Feature flags. They’re cheap-ish. Use them precipitously. I really liked using Remote Config which let me change UI on the fly in realtime, which is exactly the opposite of what I’m going to advise you in this blog.

Yes, but:

Anyway, one lesson that I seem to re-learn in every company I work for is as follows:

Do not access a feature flag in a function. It is a recipe for disaster.

There’s two main reasons:

Perf

I have seen at [redacted big company] major performance issues caused by feature-flag lookup being more expensive than people realised. Particularly in very hot code paths, such as video/audio encoders, or in scrollable UI surfaces - it can really cause you a lot of pain.

Predictability

Depending on how your feature flags are set up, they can potentially change out from under you, especially if you’re flagging/killswitching things close to startup. You might make an assumption based upon the state of a feature flag, which will turn out to not be true when your app syncs with the server. This can cause weirdness, or crashes in the worst case. Avoid this.

The fix is easy

Dead simple infact. Instead of:

if (featureFlag.somethingIsEnabled()) {
    // Do the thing
}

Make a habit of reading this once in a field:

val isSomethingEnabled = featureFlag.somethingIsEnabled()

if (isSomethingEnabled) {
    // Do the thing
}

Or pass it through the constructor instead - note that this way is simpler to test:

class ThingDoer(val isSomethingEnabled: Boolean) {
    if (isSomethingEnabled) {
        // Do the thing
    }
}

That’s it, that’s the PSA. Go forth and flag.