Feature Flag Considerations in a Microservice Architecture featured image

Feature flags are configuration settings that let you turn features on and off. They allow you to dynamically roll out features, and they make testing and deployment much easier.

In this article, you’ll learn more about feature flags and the situations in which they can help you. You’ll also see how they can be used to help you take granular control of your microservices, enabling you to test new features easily.

Why do you need feature flags?

Feature flags are essentially Boolean settings, meaning they can be set to true or false. They can be used to turn a particular feature on or off, or to enable or disable a specific version of the feature.

Once a feature flag has been implemented, you can turn the relevant functionality on and off quickly without having to hunt for it in your codebase. In many cases, you can place the flag values in a configuration file, which can save you time. In addition to being fast and easy, using feature flags can prevent you from having to rebuild or redeploy your application.

Adding or removing features with nothing more than a configuration change lets you take close control of what your applications do. With feature flags, you can add or remove features in a live application, as well as perform A/B testing on an application without having to make changes to it.

Feature flag use cases

Here are several specific use cases where feature flags shine.

Feature Rollout

Feature flags let you release features without new deployments, since you can include inactive features, then later activate them using flags accessed via an online service. 

You can deploy code that enables a specific UI feature, switching it on when you want to launch it. An updated version of a tool or new functionality can be tied to a feature flag, and enabled or disabled by changing a boolean value on a server.

In addition to working with web apps, you can do this for mobile apps, or any other kind of software. Feature flags save time by avoiding the need to redeploy, and also mean you can make changes, even if the user doesn’t update their software.

Perhaps you have a feature that you want to test more before making it available, or that you want to reveal on a particular date for marketing or technical reasons. You could launch your feature when a campaign starts, or when the infrastructure to support it is ready.

Disabling features with issues

You can also give yourself the option to remove a feature. If you want to test something in the wild, but aren’t entirely confident it will be problem-free (such situations do occur), then you can roll it out with a feature flag as a fail-safe if you need to disable it.

This allows you to simply disable the feature, effectively removing it from your live application, without having to deploy new versions of your application or rebuild all your deployments. That can save you huge amounts of time and effort.

A problem that could take weeks to solve can now be fixed in seconds, which allows you to take chances with less risk than would otherwise be the case. With the troublesome features disabled, you can focus on fixing the issues for your next release.

Testing

Feature flags are also great for testing. Most developers have, at some point, found themselves caught in a versioning nightmare where desperate efforts to fix an urgent problem result in multiple rapid releases. The minor version numbers go up and up as fixes are attempted, and soon no one has any idea who’s running which version of what.

With feature flags, you can have a single point of control that lets you switch things on and off in the same application, which is much easier to manage.

In particular, A/B testing is much easier if you can rapidly enable and disable features without modifying the rest of the software.

You don’t need to create branches and have multiple versions of your code—you just need the latest version with the flag embedded. This allows you to rapidly perform testing.

Permissions

You can use flags to grant access to specific features. For example, a subscriber on a higher-tier plan might have access to your scheduling features, while subscribers on lower-tier plans don’t.

Managers could use flags to set permissions for junior team members, allowing them user privileges such as the ability to edit documents or publish articles on a blogging platform.

How feature flags work in a microservice architecture

In a microservices architecture, managing complexity is an ongoing challenge. Feature flags are especially beneficial here, as they let you easily specify what features to activate.

If you’re using the Python Flask framework to provide microservices, you could include feature flags in your configuration as follows:

FEATURE_A_ACTIVE: False
FEATURE_B_ACTIVE: True

There are two feature flags in this example that let you switch two different features on and off. You only need one for A/B testing, but this illustrates how you can control multiple features at once by including as many flags as you need.

However, that doesn’t mean testing them both at once is best practice!

Below are two diagrams showing different ways you might use feature flags. In the first, the feature flag is being used to switch a new version of a feature on or off:

In the next, the feature flag is being used to determine if the feature is included or not:

Flask microservice example

Below is a simple microservice in Python using the Flask framework, which includes a single endpoint and a flag to turn a new version of a function on or off:

from flask import Flask, jsonify
from microservice_app.services.db_service import DB_Service

def create_app(test_config=None):
	#create and configure the app
	app = Flask(__name__, instance_relative_config=True)
	app.config.from_mapping(
    	SECRET_KEY='secret',
    	DATABASE=os.path.join(app.instance_path, 'microservices.sqlite'),
    	FEATURE_STOCK_DATES=True
	)

You can place this wherever you have your views; in this case, it’s in the __init.py__ file. You can, of course, have a function for each endpoint in here to create multiple services in the same deployment.

You list your feature flag along with other variables when creating the app. The flags could also be stored in your setup.cfg file or in-line near the start of __init.py__, like in the example. The flag is the last variable, FEATURE_STOCK_DATES. You can add as many other flags here as you need.

Here’s how the basic microservice call looks before adding the code to respond to the flag:

@app.route("/product-available/<code>")
def product_available(code):

    	data = DB_Service().check_stock(code)
    	return jsonify({"stock": data})

This is a service that returns stock levels of a product, taking the product code as a parameter and returning a JSON response showing the stock level.

If you want to test a new version of this service, you can add a flag to enable your new call. In this case, you'll write a new version of the function call to the database, and use the flag to make the call to the new function instead of the old one.

Now you can modify your microservice call to optionally use the new version of the function, depending on whether the flag is active:

@app.route("/product-available/<code>")
def product_available(code):

    	if app.config.get('FEATURE_STOCK_DATES') == True:
        		data = DB_Service().check_stock_experimental(code)
    	else:
        		data = DB_Service().check_stock(code)

    	return jsonify({"stock": data})

The new function modifies the output to include an earliest delivery date, alongside the current stock levels.

For reference, here’s the whole __init.py__ file:

from flask import Flask, jsonify
from microservice_app.services.db_service import DB_Service
from . import db

import os

def create_app(test_config=None):
	#create and configure the app
	app = Flask(__name__, instance_relative_config=True)
	app.config.from_mapping(
    	SECRET_KEY='secret',
    	DATABASE=os.path.join(app.instance_path, 'microservices.sqlite'),
    	FEATURE_STOCK_DATES=True
	)

	if test_config is None:
    		# load the instance config, if it exists when not testing
    		app.config.from_pyfile('config.py', silent=True)
	else:
    		# load the test config if passed in
    		app.config.from_mapping(test_config)


	#set up the db
	db.init_app(app)

	#ensure the instance folder exists
	try:
    		os.makedirs(app.instance_path)
	except OSError:
    		pass

    	# microservice endpoint response
	@app.route("/product-available/<code>")
	def product_available(code):

    	if app.config.get('FEATURE_STOCK_DATES') == True:
        		data = DB_Service().check_stock_experimental(code)
    	else:
        		data = DB_Service().check_stock(code)

    	return jsonify({"stock": data})

	return app

Issues to keep in mind when using feature flags

Think carefully when it comes to naming feature flags. You can call them whatever suits you, but as with all names, making it clear what they do means your code is much easier to work with.

If you have more than one flag, it's a good idea to keep them all in the same place. This allows your testers to manipulate them easily.

Changing configuration files is much easier than modifying code, so you’re potentially making things easier for your less-technical testing staff, as well as making the change procedures accessible to those who don’t work in the language your application is built in.

Feature flags create branches in your code, which can get confusing and messy. The more there are, the more complex your code gets. It can also lead to code coverage issues. If you only test with specific flags set, then alternate branches won’t be covered.

You need to make sure your tests include all branches a flag could lead to. For A/B testing, this often isn't as much of an issue, as you're likely to remove tests once you’ve determined what works. For long-term feature switching, though, you need to factor this in to make sure your tests hit full coverage.

For maintenance, removing old flags keeps things from getting out of control. When a feature is finished or a bug is fixed, you can remove the relevant flags. There are SaaS feature flag platforms that keep detailed logs of what flags are in current use, making this process much easier.

Wrapping up

Feature flags are very simple, but don’t overlook their power. They make testing and deployment much easier and can save you big headaches when rolling out and testing features. They allow for a level of flexibility that wouldn’t otherwise be possible.

Have a look at your own deployment and testing practices and see if there’s room to use feature flags. They can increase your agility and make it easier to add functionality and get it in the hands of your users.

Related Content

More about Best Practices

February 21, 2023