Mastering configuration for multi-environment web applications

Mastering configuration for multi-environment web applications

Setting expectations 

This article is aimed at technical people that have interacted with a web application. It sets the foundation for a series of articles where I am talking about configuration management for web applications. 

Throughout the articles, I will consider a fictional, single page web application, called Meowsee. It allows cat owners to share pictures of their cats doing funny things, identify breeds and connect with other owners around the world. The application is actively developed by a team of a few hundred engineers spanned around multiple geos, following a continuous deployment model. 

Article content

What’s the deal with configuration? 

Modern web applications, such as Meowsee, can run either in a browser or embedded in a shell, in the case of hybrid mobile applications, and connect to various backend services. We can refer to the web application as to the client

To be functional, the client needs information such as: the URLs and API keys for backend services, what is the display order of various content sections, whether specific functionalities are enabled or not for an end user etc. This information is generally called configuration, and it is split into feature flags and settings

Settings and feature flags can be similar and quite different at the same time. Let’s see what they are and when to use one versus the other:

  • we can think of a feature flag as a variable having a binary value, usually boolean true/false, controlling the availability of a functionality. Imagine Meowsee integrates a brand-new functionality that allows people to understand what cats are saying, but it is still in test. We can define a variable allowMeowTranslation which controls the availability of this revolutionary functionality - allowMeowTranslation is a feature flag. Assigning allowMeowTranslation to true means that people can use Meowsee to translate feline dialect, while false means the functionality is disabled. With other words, a feature flag enables continuous integration, is the base for staged or progressive rollouts and helps product growth teams to make business decisions by running experiments. 
  • a setting is modelled as a variable as well, with no limits regarding the possible values and /or data types. If the feature flag tells us whether the functionality is available or not, a setting provides the parameters required for the functionality to run. In our cat translation example, when the allowMeowTranslation feature flag is enabled, the app connects to an API to translate the feline dialect. The API requires an API key to handle client requests. These two pieces of information, the API URL and API key, are the settings and we can give them a name and a value: meowTranslationApiUrl=”https://meow-translation.com/api/v1” respectively meowTranslationApiKey=”meow1meow2meoooow3". 

Article content

Moving forward with this example, the Meowsee app requires a feature flag (allowMeowTranslation) and two settings (meowTranslationApiUrl, meowTranslationApiKey) to integrate the translation functionality – sounds easy to manage, right?  

The challenge of managing configuration 

Well, managing a 3-dimensional configuration sounds simple enough, but there are some challenges that might not be so obvious in the beginning: 

  • Meowsee app has several running environments (local, dev, stage, production) 
  • the translation functionality must be disabled for all environments by default, as long as it is in development 

  • for each environment we have a different API URL and key to use for connecting to the translation service 

  • quality engineers must be able to enable the functionality on any environment at any time 

  • product managers need to conduct user testing and interviews before the release, and they need the translation functionality enabled in Meowsee  

  • engineers and managers need to be able to track the changes – when and who did what – to debug possible issues generated by wrongfully altering configuration 

So how do we manage all the possible combinations to keep everyone happy, while ensuring high quality standards for what is delivered in production? 

Article content

Enter configuration overrides 

The solution is to allow configuration to be overridden at runtime and load time. The idea relies heavily on object-oriented programming and sounds like this: 

  • a centralized module exposes signatures for setting and feature flag classes together with a configuration manager class 

  • each setting and feature flag instance works behind the scenes with an instance of the configuration manager to resolve their value. It goes without saying that the configuration manager is implemented using the singleton design pattern 

  • software engineers define setting and feature flag instances in the codebase of the application, with default values - it is good practice to have a single location/file that holds these definitions 

  • when the value of a setting or the state of a feature flag is evaluated, the call is forwarded to the configuration manager who is responsible to calculate the final value 

  • the configuration manager checks and returns the value based on a priority order as following: 

  1. with priority 0: a local browser storage – for instance IndexedDB. Developers can write overrides here using the developer console offered by all browsers nowadays 
  2. with priority 1: a programmatic source of configuration overrides. This can be the result of an API call or a global configuration object that is injected into the application at load time 

Article content
a diagram of the solution

Now we have defined a solution that fulfils the requirements mentioned above: 

  • configuration changes can be tracked using the source versioning system 

  • feature flags and settings can be overridden at any time by software engineers and product managers, either for their current session or for all users of the application 

  • settings can have different values, depending on the running environment and a default value to fall back to in case the override providers aren’t working 

Article content

One environment, countless configuration flavours 

But how exactly do software engineers and product managers manage to do their job in a timely manner if they must always start by defining configuration overrides?  

Meowsee solves this by allowing engineers to define custom routes to override configuration. When accessing the route, the user sees the application loading normally, just as it does on the default route. 

For instance, if we consider https://meowsee.cat to be the application’s host, then we can imagine the following routes: 

  • https://meowsee.cat/translation-enabled is a custom route where the translation functionality is enabled with the following feature flag override: 

allowMeowTranslation=True          

  • https://meowsee.cat/translation-engine-v2 is another route where we are testing a new translation engine: 

allowMeowTranslation=True 
meowTranslationApiUrl=”https://meow-translation.com/api/v2”         
Article content

Wrapping things up 

We have defined what is a setting and a feature flag and when to use each. Then we saw what the hidden challenges are when configuring web applications and how we can deal with them.  

In the next article I will go into more details about how Meowsee’s custom routes work and how they go hand in hand with caching at the edge and authorization checks. I will tackle things like CloudFront, Lambdas and K8s. Stay tuned! 

To view or add a comment, sign in

More articles by Marius Ioan Sofron

Others also viewed

Explore content categories