Mastering Feature Flags: A Comprehensive Guide
Written on
Chapter 1: Understanding Feature Flags
Feature flags, also known as feature toggles, are configurations that dictate how software operates and which features are active or inactive. It's essential to set up feature flags on the same host where our software operates, utilizing structured data formats. This practice ensures that they are efficient, reliable, and manageable.
Why Implement Feature Flags?
Utilizing feature flags enables the integration of unfinished features into our software without jeopardizing overall system stability. They facilitate testing in production and allow for gradual feature releases to select user groups, which is advantageous for continuous integration and frequent code delivery.
Feature flags can range from simple environment-based configurations to intricate setups that adjust functionality for various users over time.
Avoiding Network Calls
When configuring feature flags, it’s preferable to do this on the software's host rather than relying on external network calls. Network requests can lead to outages, increased response times, and complicate management efforts.
Network Call Challenges
Accessing feature flags via network requests can cause failures due to throttling, especially in serverless or dynamically scaling environments. While caching flag values locally can help mitigate this issue, it can also add complexity to the codebase and introduce additional caching-related problems.
The latency associated with network calls can be unpredictable compared to the quick response times from local environments. If feature flags are stored externally, changes may occur independently of the host, leading to potential misconfigurations in a live setting. It’s more efficient to adjust feature flag settings alongside the service and test thoroughly before deploying.
Avoiding Environment Variables
Environment variables are often employed to pass configuration values to command-line interface software. While this method is straightforward, it’s advisable to steer clear of using them for feature flag configurations.
Limitations of Environment Variables
Environment variables are restricted to string values, necessitating parsing into appropriate data types for software that reads or writes them. This parsing adds unnecessary complexity.
Additionally, environment variables are global within a process, requiring structured keys to be flattened. For example, to set a property C of group B in software A to 9090, the variable would need to be defined as: A_B_C="9090". This flattening complicates management.
Packaging and using environment variables is also cumbersome, as they are loaded at runtime. While exporting from a file before execution is one workaround, a better solution exists.
The Optimal Solution
We can effectively manage feature flags by incorporating a structured data file, such as JSON or YAML, within our software directory as config.json/config.yaml. This file can be loaded at startup and parsed using built-in tools, allowing for various data types and organized configurations.
For instance, a configuration file in JSON might look like this:
{
"features": {
"customer_icon": {
"enabled": true},
"billing_alerts": {
"release_date": "2022-08-06"},
"date_format": "%Y-%m-%d",
"console": {
"version": 1.0}
}
}
Here’s an example in YAML:
features:
customer_icon:
enabled: true # Comments are possible in YAMLbilling_alerts:
release_date: '2022-08-06'date_format: "%Y-%m-%d"
console:
version: 1.0 # Update to version 2.0 soon
By keeping feature flag configurations on the host, we significantly reduce latency and prevent network-related outages. This approach also avoids the constraints of environment variables, enabling us to structure data efficiently.
Using Feature Flags in Code
To utilize these feature flags, we simply load them and toggle functionality based on their values. Below is a Python example demonstrating this:
import datetime
import json
# Load JSON File
configuration = json.loads(open('./config.json', 'r').read())
# Date Format
date_format = configuration['features']['date_format']
print("Using Date Format:", date_format)
# Today's Date
date_today = datetime.datetime.today()
print("Today's 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 example illustrates how to enable or disable features, schedule functionality releases, and utilize built-in data types for configuration management.
Summary
Using structured configuration files is the most effective way to manage feature flags while avoiding network-related issues and the complications of environment variables. This method can also centralize the management of environment-specific settings.
There are numerous additional advantages to using structured files for software configuration that haven’t been covered here. We encourage you to reach out if you have any questions or if this solution has been beneficial for you.
Stay connected for more insights or contact me at:
Twitter: @BenTorvo
Email: [email protected]
Website: torvo.com.au
Level Up Coding
Thanks for being part of our community! More content is available in the Level Up Coding publication. Follow us on Twitter, LinkedIn, or subscribe to our newsletter.
Level Up is transforming tech recruiting! Join our talent collective.
Discover how feature flags extend beyond simple toggles, enhancing software development processes.
Get a concise overview of feature flags in just 6 minutes, exploring their importance and application in development.