Features.js: poor man’s Gatekeeper

We want to release our UI code frequently, but we also want to be able to check in code for features that are not ready for release.  Facebook has Gatekeeper, a sophisticated piece of infrastructure that allows them to enable or disable features in production on a per-user basis.
gatekeeper
We want that too, but we’re not ready to make something so complicated. We decided we can get 80% of the bang for 5% of the buck. We don’t REALLY need per-user settings, and we don’t REALLY need the ability to change settings at runtime. What we really need is just a way to turn on or off Javascript based on environment. For example, a feature might be turned on for developer deploys, but not in production deploys.
We built Features.js, some simple-as-dirt Javascript code that allows developers to protect their code with IF statements based on environment.
dirt
Here’s an example of what a developer might write if they want to control the visibility of a feature based on the Features.js settings:

if (fe.on(fe.NIFTY_FEATURE)) {
  //Implement nifty feature
}

And here’s what the implementation looks like:

var fe = {};

// Possible states for a feature
fe.EnabledState = {
  ENABLED: 1,        // On for everyone
  DISABLED: 2,       // Off for everyone
  DEV_OR_QA_ONLY: 3, // On when running for dev, or on QA servers.
                     //  Use this when the feature should be visible to QA,
                     //  but not available on the extranet.  NOTE: This
                     //  turns the feature OFF on staging, which lets you
                     //  verify that the feature will be correctly disabled
                     //  in prod (since staging and prod are treated
                     //  identically.)
  DEV_ONLY: 4,       // On when running for dev (not on EC2)
};

// Features that can be turned on or off. To add a new feature, create
// a new block like the following.
fe.NIFTY_FEATURE = {
  enabled: fe.EnabledState.DEV_ONLY
};

// Helper function which returns a boolean indicating if the
// supplied feature is turned on in the current context.
fe.on = function(feature) {
  if (feature.enabled === fe.EnabledState.ENABLED) {

    // Enabled- always return true
    return true;
  } else if (feature.enabled === fe.EnabledState.DISABLED) {

    // Disabled- always return false
    return false;
  } else if (feature.enabled === fe.EnabledState.DEV_ONLY) {

    // Logic specific to your implementation
  } else if (feature.enabled === fe.EnabledState.DEV_OR_QA_ONLY) {

    // Logic specific to your implementation
  }

  // Features are off by default; if there's a bug with the config, the
  // feature should be turned off
  return false;
};

Posted in Engineering

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: