How to Use Feature Flags

Feature flags or feature toggles are settings that control how software runs and which features are enabled or disabled. Feature flags should be configured on the same host our software runs on using structured data formats to ensure that they are performant, stable and easy to manage.

Feature Flags

Why Use Feature Flags

By using feature flags it is possible to integrate incomplete functionality into our software without breaking the whole system. Feature flags also allow us to test in production environments and roll out functionality to small groups of users at a time. This can be helpful when aiming to continuously integrate and deliver new code on a frequent basis.

Feature flags can be as simple as enabling features based on the environment, or as complex as modifying what functionality to use for different users at different points in time.

Avoid Network Requests

When we configure feature flags we can do so on the host that is running our software or somewhere else over the network. However, we should avoid making network requests to get our feature flags because it can increase outages, slow down our systems and make changes harder to manage.

Network Requests

If feature flags need to be accessed over a network, any time a host handles a request it can cause failures due to throttling. This can be common for processes running in serverless environments or environments that scale up and down frequently. The problem of throttling can be mitigated by getting the values and caching them locally or in a data store, but doing so can increase code complexity whilst also introducing more issues related to caching.

When feature flag configuration is accessed via a network call the latency of any request increases based on the response time of that system. This can cause long and unpredictable latency compared to the consistency of making a request to the local environment.

If feature flags are stored externally the values and system that manages the configuration may change separately to the host that needs the flags. This can lead to configuration changes being modified in production with potential outages if things are misconfigured. Instead it is better to change the feature flag configuration with the service and test them before releasing the software.

Avoid Environment Variables

Environment variables are often used to pass values to command-line interface software that needs configuration. This is a quick and easy way to change settings but we should avoid using them to configure feature flags.

Environment Variables

Environment variables are limited to string only, so any software that needs to write or read environment variables needs to parse the strings into appropriate data types. This complexity is extra work on both the software and any tooling that manages the software, which shouldn't be necessary.

Environment variables are not structured and are globally scoped within a process, which means that any structured keys need to be flattened. As an example, to set the property C of group B within software A to the value 9090 we would need to flatten the environment variable as:

A_B_C="9090"

This extra parsing and global scope can lead to even more complex handling of the environment variables.

It is hard to package and include environment variables with software as they are loaded in at run time. To set the values we need to run commands or a script setting the values on the host for the shell that the software runs in. One option is to load them from a file by exporting everything in it just before running the software. This works, but there is a better way ...

The Solution

We can configure the feature flags for our software by including a structured data file such as JSON/YAML within our software directory as config.json/config.yaml. We can then load this file when our software starts and parse it with built in tooling. We can use built in types as well as structured config for different flags.

config.json

{
    "features": {
        "customer_icon": {
            "enabled": true
        },
        "billing_alerts": {
            "release_date": "2022-08-06"
        },
        "date_format": "%Y-%m-%d",
        "console": {
            "version": 1.0
        }
    }
}

config.yaml

---
features:
  customer_icon:
    enabled: true # We can also write comments in yaml
  billing_alerts:
    release_date: '2022-08-06'
  date_format: "%Y-%m-%d"
  console:
    version: 1.0 # Should be updated to 2.0 soon

We can avoid network issues by storing the feature flag configuration on the host running the software. By including it as a file on the host we reduce the latency to almost 0 and avoid outages caused by network failures.

We can also avoid the limitations of environment variables by using structured data formats such as JSON and YAML. This lets us structure our data appropriately and use built in types other than strings.

To use these feature flags we just load them in and switch functionality on or off depending on the values. Here is a Python example:

import datetime
import json

# Loading JSON File
configuration = json.loads(open('./config.json', 'r').read())

# Date Format
date_format = configuration['features']['date_format']
print("Using Date Format:", date_format)

# Todays Date
date_today = datetime.datetime.today()
print("Todays Date:", date_today.strftime(date_format))

# Billing Alerts
billing_alerts_release_date = datetime.datetime.strptime(
    configuration['features']['billing_alerts']['release_date'],
    date_format
)
print(
    "Billing Alerts Release Date", 
    billing_alerts_release_date.strftime(date_format)
)
if billing_alerts_release_date < date_today:
    print("Billing Alerts Are Enabled")
else:
    print("Billing Alerts Aren't Enabled Yet")

# Customer Icon
print(
    "Showing Customer Icon", 
    configuration['features']['customer_icon']['enabled']
)

# Console Version
print(
    "Using Console Version", 
    configuration['features']['console']['version']
)

This is how we can enable or disable features, release functionality on a specified date, and use built in types to manage our configuration.

Summary

Structured configuration files are the best way to manage feature flags without worrying about network issues or parsing everything in and out of environment variables. This can also be used to manage any environment specific settings within our system as a central point of control.

There are many more positive side effects of configuring software with structured files that we haven't covered yet. Let us know if this solution works for you or if you have any further questions.

Follow me here for more content or contact me on: