Introducing JSON Toggle

This post proposes JSON Toggle, a JSON document structure for specifying feature toggles. This format is being used at Whisker Labs with a Java 8 library which we’re open-sourcing as a proof-of-concept for JSON Toggle.

Background

Feature Toggles (or feature flags) are a programming mechanism used to dynamically configure running programs. A team utilizing feature toggles can modify a software system’s behavior without having to redeploy code or restart processes with new configuration. When used judiciously, feature toggles can dramatically increase a team’s rate of experimentation and delivery.

The state of a collection of feature toggles is typically read at runtime from some side channel such as a database or a config file. This state can be updated out-of-band with tooling (e.g. a dashboard) and automatically distributed to running applications. At Twitter (where I used to work), the company-wide feature flag system provides the software equivalent of a railroad switching station, giving teams dynamic control over which codepaths were enabled for which users. This level of flexibility unlocks the ability to roll out new features and perform large refactors with a minimum of pulled-out hair.

A protocol for defining feature toggles

Since their emergence in the late aughts, feature toggles have become a common pattern at internet companies and have made their way into the enterprise. Despite this, there has never been a successful effort to standardize the means by which toggles are configured. By and large, the state of the art has each organization building an implementation from scratch and maintaining a bespoke distributed CRUD app to manage them.

It’s shocking to me that there isn’t an equivalent of the statsd protocol for feature toggles. Regardless of the storage and distribution mechanism used, a protocol would at least allow us to converge on a standard for specifying toggle configuration.

With this in mind, I’d like to propose JSON Toggle, a feature toggle specification format that we’re starting to use at Whisker Labs.

JSON Toggle defines a JSON document structure for parameterizing a set of feature toggles. Such documents, called “toggle specifications”, may be used to enact weighted probabilities that determine whether or not a feature is enabled for a given request.

JSON Toggle is language-agnostic in the sense that ingestion libraries may be implemented in any programming language.

An example toggle spec

In the following example toggle specification, three toggles are defined:

  1. "/feature/ab_test" which acts as a simple coin-flip with 50% probability.
  2. "/feature/dogfood_widget" which can be used to guard a feature that is 100% accessible to employees but inaccessible to all other users.
  3. "/feature/incremental_rollout" which grants access to all employees, but only 1% of non-employee users.

The spec looks like this:

[
  {
    "key": "/feature/ab_test",
    "value": 5000
  },
  {
    "key": "/feature/dogfood_widget",
    "filter": [{
      "type": "cohort",
      "target": "employee",
      "value": 10000
    }],
    "value": 0
  },
  {
    "key": "/feature/incremental_rollout",
    "filter": [{
      "type": "cohort",
      "target": "employee",
      "value": 10000
    }],
    "value": 100
  },
  ...
]

Or equivalently in YAML:

---
- key: "/feature/ab_test"
  value: 5000
- key: "/feature/dogfood_widget"
  filter:
  - type: cohort
    target: employee
    value: 10000
  value: 0
- key: "/feature/incremental_rollout"
  filter:
  - type: cohort
    target: employee
    value: 10000
  value: 100

For each specified toggle, an integer value from zero to 10,000 represents a probability (out of 10,000). These values can be thought of as weights for predicates (boolean-valued functions) that are used in application code to guard whether or not a feature is enabled for a given request.

Toggles can additionally specify filters which apply different probability values to certain types of requests. For example, a filter could be used to target a cohort of users, such as “employees” or “beta testers”.

Toggle Specification specification

An individual toggle definition is broken into three components:

  • A required key string which uniquely identifies the toggle within the toggle spec.
  • An optional filter property, defining a list of filters which define “special case” branches of the toggle.
    • For instance, a cohort filter is used to match a toggle invocation with a cohort. A cohort target could identify a subset of a userbase (e.g “employees”), an IP range of incoming requests (e.g. 67.174.128.0/24), or any other subdivision relevant to an application.
    • Filters should be evaluated in the order that they appear in the toggle specification.
  • A value property, which sets the “base” value for cases when no filter applies to a request. Values are specified in basis points and define toggle probabilities out of 10,000. Thus a toggle value of 5,000 will result in a toggle probability of 50%.

A Java 8 library for working with JSON Toggle

In addition to this protocol, I’d like to share an early version of a JSON Toggle ingestion library that we’re using at Whisker Labs for our Java services. toggle is a Java 8 library which implements the functionality described above using java.util.function primitives. It supports toggle specifications stored in Amazon DynamoDB tables or JSON/YAML files, and offers a caching decorator powered by Caffeine.

With this library, we can do things like this:

// Construct a caching `ToggleMap` backed by a DynamoDB table.
Table dynamoDbTable = dynamoDbClient.getTable("production-toggles");

ToggleMap<String, Integer> toggleMap = new CachingToggleMap<>(
  new DynamoDbToggleMap<Integer>(dynamoDbTable),
  "maximumSize=1000,expireAfterWrite=1m"
);

// Create a toggle backed by the "/feature/new_hotness" definition.
Toggle<Integer> fancyNewFeature = toggleMap.apply("/feature/new_hotness");

// Use the toggle to guard some new functionality, based on a user ID.
if (fancyNewFeature.test(user.userId)) {
  // New hotness.
} else {
  // Old and busted.
}

Nomenclature unabashedly cribbed from Finagle.

Now what?

If JSON Toggle is to become a thing, we’ll need to write ingestion libraries in other programming languages and various tools to make it easy to manage with toggle specifications.

If you think this approach could be useful or that it’s a stupid idea, I’d love to hear from you. In lieu of an official channel like a mailing list, for the time being, please reach out via email or by filing an issue on the toggle project on GitHub.


Thanks to Rishi Ishairzay for reading and providing feedback on drafts of this essay.