Skip to content

Instantly share code, notes, and snippets.

@threepointone
Last active May 24, 2023 11:03
Show Gist options
  • Star 59 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • Save threepointone/2c2fae0622681284410ec9edcc6acf9e to your computer and use it in GitHub Desktop.
Save threepointone/2c2fae0622681284410ec9edcc6acf9e to your computer and use it in GitHub Desktop.
Feature flags: why, how, all that

(I'm enjoying doing these raw, barely edited writeups; I hope they're useful to you too)

Feature flags

This is my own writeup on feature flags; for a deep dive I'd recommend something like Martin Fowler's article (https://martinfowler.com/articles/feature-toggles.html).

So. Feature flags. The basic idea that you'll store configuration/values on a database/service somewhere, and by changing those values, you can change the user experience/features for a user on the fly.

Let's say that you're building a new feature, called 'new-button' which changes the color of buttons, which is currently red, to blue. Then you'd change code that looks like this -

function Button(props) {
  return <button style={{ backgroundColor: "red" }} {...props} />;
}

to this -

function Button(props) {
  const isNewButton = useFlag("new-button");
  return (
    <button
      style={{ backgroundColor: isNewButton ? "blue" : "red" }}
      {...props}
    />
  );
}

(NB: This is a completely made-up implementation, I used a hook here just because.)

This is as simple as it gets. The value of isNewButton is fetched from a service somewhere, usually just once for the lifetime of the application (possibly right when the application starts?) Someone could then go to a hosted page somewhere listing all the configuration values, flip a switch, and decided whether to turn the button color red/blue. Flags don't have to be just booleans; they could be strings, or numbers, or any other values as well.

But wait. Some of this sounds like over-engineering. Why not simply have a module (say, features.js) that exports an object with these values? You could change them whenever, commit and deploy, and that would achieve the same thing. Or if you're going to use a service, why not a regular configuration service? Or a regular key value store with a simple UI on top of it?

The answer is targeting.

Feature flag services let you serve different values for different groups of people (based on whatever conditions you choose.) Typically, they'll integrate with some form of user service that you're using in your application/firm, and you'll be able to target values based on identity (like a user id), some grouping condition (like, what teams/groups a user belongs to), or a bucketing system (e.g - only for x% of users, where x can be dynamically changed at any time). This is an incredibly powerful feature that lets you achieve many things:

  • mainline development: All PRs directly target your main branch. All new features are wrapped in a feature flag, and are turned on and off only once in a deployed environment. This also means you only need to deploy in-progress work to one environment/server, instead of needing different targets for different PRs, for example.

  • prototypes: Want to build a quick product idea and share it with (only some) people? Put it behind a feature flag, add those people to the flag's filter, done.

  • demos for stake holders: similarly, if you're building some cool stuff and want to impress your boss, or their boss, or some new client; feature flags ftw.

  • qa on prod: Instead of deploying new changes to another environment for QA (realistically, a farm of machines, for every new feature being developed), the application can be deployed to production directly, turning on features for QA/UAT folks either manually by IDs, or targeting their team as a group. Once they signoff on features, it can be turned for users without any new deploys or releases.

  • gradual rollouts: You can mark feature flags are being turned on/to a particular value for a given percentage of users. This lets you roll out the feature gradually; you can observe analytics to make sure nothing is broken and you're seeing expected results (based on what the feature achieves), and if all is going well, roll it out to more people. Similarly, if you see something wrong, or start getting bug reports about something being broken, you can turn it all the way down without a fresh deploy, which gives you time to investigate and fix the problem. Super neat.

  • (Y'all got any more ideas? Lemme know.)

Notes

  • You want to be sure that your application is resilient to the feature flag service failing; i.e. make sure the 'default' choice is the safe choice.

  • You may get concerned that your codebase will end up as a tangle of if-conditions, littered with feature flags. This is a good problem to have; a better problem than not being able to ship features, getting mired by infrastructure/architecture/process problems! I would recommend doing a regular cleanup; you could possibly run a script on your codebase every month or so, and detect flags that are set at 100% in production. Your script could get smart and codemod out the branch as well.

  • A concern is that you'll end up shipping more code to a user than is generally used/required for the application. This is valid, and as such, feature flags for front end development are probably best for applications where bundles size isn't the most critical metric. Suggestions to improve this could be using dynamic imports for features (i.e. - condn? import('feature1') : import('feature2')), to integrating your build system with your feature flag service, generating multiple bundles based on combinations of feature flag values, and serving the right combination of bundles to your users (this is what big corps like fb do.)

  • How do you write tests for stuff behind feature flags? You would mock the feature flag service itself, and set the required flags to the values you need for the tests you're running. Nice.

  • Some examples of third party products (I haven't used any of these myself): LaunchDarkly, Optimizely, ConfigCat, split

  • Some good counterpoints here https://software.rajivprab.com/2019/12/19/when-feature-flags-do-and-dont-make-sense/

(todo: write about how to query values inline, but fetch all values at the beginning).

@threepointone
Copy link
Author

@sw-yx I have an idea here to do it without suspense. Consider -

  • enforce that the value passed to useFlag() is always a string literal so it can be statically analyzed.
  • run a script on the codebase and collect all the arguments passed to useFlag
  • for every main request to an html page, fetch all these values and inline as a global js object

useFlag will then always be sync, and values always available. It doesn't even have to be a hook, can be a regular function call anywhere.

@swyxio
Copy link

swyxio commented Aug 8, 2020

totally. i think there is some unnamed pattern in our future where it will be normal to statically extract all sorts of metadata from our code to run it upfront. with typescript we extract types. with gatsby and relay we extract graphql. with purgecss and babel we extract css.

why not more things? should all these be separate tools or should they be 1 tool with just a bunch of callbacks people can hook in to? why run this extraction/analysis/validation only at build time - why not always have it on? this is why i think the future is a generic "language server" for frontend dev that handles all this.

@NMinhNguyen
Copy link

NMinhNguyen commented Aug 9, 2020

A concern is that you'll end up shipping more code to a user than is generally used/required for the application. This is valid, and as such, feature flags for front end development are probably best for applications where bundles size isn't the most critical metric. Suggestions to improve this could be using dynamic imports for features (i.e. - condn? import('feature1') : import('feature2')), to integrating your build system with your feature flag service, generating multiple bundles based on combinations of feature flag values, and serving the right combination of bundles to your users (this is what big corps like fb do.)

Is creating different bundles (like React bundles with its buildtime feature flags) noticeably better than dynamic imports? Roughly what is required to implement this serving of different bundles? SSR?

@threepointone
Copy link
Author

@NMinhNguyen there's a major difference between creating different bundles like React does, vs what facebook does with application code. React's bundles are based on predefined channels (defined in https://github.com/facebook/react/blob/master/scripts/rollup/bundles.js). Of note, this does not account for every variation/combination of feature flags, just the ones explicitly defined in ReactFeatureFlags.* in https://github.com/facebook/react/tree/master/packages/shared/forks. What I was referring to was having bundles available for every possible combination of feature flags (which would be a loooot more). It requires your bundler to be able to smartly generate chunks for these combinations, and then include them on your page based on the user visiting. There aren't any publicly available tools that do this, because it usually requires deep integration with your serving infrastructure, feature flag and identity services, etc.

@threepointone
Copy link
Author

@NMinhNguyen That said, it's not as big a concern if bundle size isn't you primary performance metric. It's fine to ship some extra code as long as you're diligent about cleaning up, and don't let it inflate beyond some critical number (like, don't accidentally send MBs of code)

@NMinhNguyen
Copy link

Oh right, I just assumed that at Facebook, a lot more bundles of React were generated (re-built), e.g. various combinations of https://github.com/facebook/react/blob/0cd9a6de557f44dcfe79a4f287ca04b05d674bdc/packages/shared/ReactFeatureFlags.js#L44-L45 or any other new experimental feature.

@vacom
Copy link

vacom commented Aug 9, 2020

Hey I am the creator of https://www.upstamps.com

UpStamps is a Feature Flag Management Platform that lets you manage every feature with a central visibility and control user interface. Teams and developers are managing their projects using feature management to progressively deliver features to users with confidence.

Key Features:

  • 📄 Create Projects
  • 🌳 Organize by Environments
  • 🧪 Run A/B Tests
  • 🏳 Deploy with Feature & Remote Flags
  • 🎯 Target Specific Segments

Nice Gist, UpStamps uses a lot of the pattern in your post. Support with React Hooks

@dreamer01
Copy link

Worked on something similar where I had to show/hide eye icon in secret fields depending on the flag for each deployment.
But I used an object configuration for that, which was requested from the BE service during project initializing phase.

Your approach would be helpful, when we decide to move control to client side also.

@fokusferit
Copy link

This is valid, and as such, feature flags for front end development are probably best for applications where bundles size isn't the most critical metric.

I think the Feature Flag implementation / architecture would have more influence maybe? You might end up having your HTTP calls (wrong API design) influence UX and Rendering more.

Like in one of our web apps, the API's are called multiple times (e.g. 3 AB-Tests on a page -> 3 separate Calls) which could have more influence. That said, in another application, we are sending all running flags for a userId immediately from one Endpoint, so it ends up being some sort of configuration service and initially can be faster except you end up having 1000+ of Flags and parsing them might be another issue 🤔

@oriSomething
Copy link

oriSomething commented Dec 16, 2020

I'm might miss it. But there is also an issue, which feature is per machine and which per users,
And what happens when for some user a feature is opened but then come another user on the same machine which the feature isn't open for them. Most cases it doesn't matter, sometimes it's critical

@electriccode
Copy link

electriccode commented Dec 16, 2020

Keep in mind that Google should always see consistent behaviour so its worth falling back to a default bucket for SEO purposes else it will impact your SEO rankings.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment