In this blog post, we show you how to separate configuration from code, explain the differences between dynamic and static configuration, and help you determine which values to use in your dynamic configuration. We also share processes to keep bloat down in your application configuration. Finally, we introduce you to AWS AppConfig, which allows you to create, validate, and deploy your application configuration. After you read this blog post, you should have practical knowledge about how to manage your application’s dynamic configuration.
Separating code from configuration
It is an established best practice to separate application configuration from application code. This separation makes it possible for you to manage code and dynamic configuration as independent entities. This means that you can change configuration separately from code and have different processes and even pipelines for releasing your configuration. The risk profile of changes in code is different from the risk profile of changes in configuration. By definition, configuration is intended to be changed, possibly frequently. But code, while flexible, can often be riskier to change. This separation helps you keep things organized and isolate risk.
Not all variables or values in the code should be separated into a dynamic configuration file. Some values, such as environment variables like Development, QA, and Production, are considered static configuration. Those values are deterministic and will not be changed during the lifetime of that software running in that environment. Values that might change from one environment to another should be in static configuration. Values that might change during the lifetime of an active software-running instance should be managed as dynamic configuration.
In this blog post, we focus on dynamic configuration. Here are some examples of dynamic configuration:
- You as a DevOps engineer might decide to put throttle limit values into an external configuration file. You adjust the throttling limits up and down to tune the application according to load, which could change by the hour or even by the minute.
- You as an application engineer might deploy a new feature, but hide it behind a feature flag. When it’s time to release the feature (in coordination with a marketing event, for example), the configuration for that feature flag can quickly and safely be changed. The feature then becomes available to customers in near-real time. These changes are made in configuration so there is no need to redeploy your whole code stack.
The separation of configuration and code helps to improve availability and engineering velocity. AWS AppConfig is used to validate and manage your dynamic configuration and deploy it in a measured and safe manner. Many AWS customers use this best practice: they treat their configuration carefully, and effectively use configuration to improve their operational posture and release features.
But how do you know what to externalize and what to keep in the code? What are mistakes and anti-patterns for separating configuration from code? And how would you manage ongoing hygiene of configuration? The following section answers these questions.
What goes into your dynamic configuration?
Configuration is any value in the code that an engineer anticipates will need to be changed easily in the future or might vary according to environment conditions:
- Feature flags
- A/B testing
- Debugging and logging attributes
- Allow lists or deny lists
- Operational tuning (throttling limits, connection limits, URIs)
- Database failover configuration
All of these items are designed to be changed over time. And because the values exist in configuration and not code, the dynamic configuration values can be changed without a full deployment or restarting the application. It’s safer and faster to push an update of the configuration, and the application can apply those changes quickly.
Three questions for creating configuration
Because you can easily, safely, and quickly make changes, you might be tempted to put as many variables as possible into your configuration. That allows you to change anything, anytime!
But overloading configuration is a bad idea. In reality, many values will never need to be updated. Externalizing them all into a separate configuration can cause dangerous and unexpected things to occur. It also creates more cruft in your configuration file, which leads to miscommunication and mistakes.
To determine what to include in your dynamic configuration, ask yourself these questions:
1. Will this value need to change in the future, and if so, how frequently?
It might seem obvious, but carefully consider if this value will need to be updated in the future. Think of some scenarios in which the value might need to change. Likelihood of change is a key indicator of the need to externalize configuration. Every creative engineer can probably brainstorm a scenario in which a value in the code could change, but how likely is that scenario?
2. Is there a scenario where, in a crisis or a feature launch, it would be helpful to change this value quickly without redeploying and restarting the app?
Many teams use operational configuration to toggle things like logging verbosity so they can see more details about problems in production. Updating dynamic configuration to address critical issues can be helpful for operations.
3. Is the value deterministic? That is, is the value important only at startup or at runtime, too?
If the value is something that you need at initialization, it should be in static configuration. If you think that changing the value during runtime would be helpful, it is dynamic configuration.
These questions should help engineers determine if a value should be externalized into dynamic configuration. There might be other questions to ask, too (for example, about business needs, team size, code complexity, and more), but these questions are foundational for your decision making. You might want to add more decision points that apply to your application or use case.
Important: When working with configuration, always make sure that there are default configuration values in the code. This means that the system can keep running even if the configuration is not available. Because code and configuration are separate, it’s possible that the code might not be able to read configuration externally. If the configuration is not present, the code should be able to use a safe default and continue to operate.
Avoid configuration bloat
Over time, it is possible to load up your configuration with too many items. On larger teams or older code bases, it is common to have esoteric or poorly named configuration flags that you are afraid to touch. Although it seems easier in the short term to leave those values in the configuration file and deal with them later, which may never happen.
Here are some best practices for managing configuration cruft:
- When you implement a new feature, always add a task to your backlog to clean up specific configuration in the future.
- Put a quarterly reminder on the calendar to clean up configuration you no longer need.
- Establish a team budget that restricts the number of allowed configuration items to a reasonable number. If you implement a new configuration item, and your configuration is at the top of its budget, you must first clean up old configuration before you add new configuration.
This decision-making framework should help you determine what an engineer should put into configuration, what should be left out, and how to keep the configuration from becoming bloated.
After you have well-constructed dynamic configuration, you can use AWS AppConfig to manage and deploy your configuration. AWS AppConfig helps you create, validate, and strategically deploy application configuration. You can deploy configuration as gradually or quickly as appropriate. With AWS AppConfig, you can also set up monitoring (for example, you can create an Amazon CloudWatch alarm and have your configuration changes rolled back when it goes off).
This post helps your team be more responsive and improves the safety posture of your operations. Happy configuring!
About the Authors
|Mark Lundquist is a Senior Software Development Engineer at Amazon Web Services. His focus is on AWS AppConfig and previously AWS Elastic Cloud Computing (EC2). Prior to working at AWS, Mark worked for multiple startups in Silicon Valley and the DC area.|
|Steve Rice is the Principal Product Manager for AWS AppConfig. He loves building products that improve customer’s lives, and is passionate about dynamic configuration and helping developers make application changes as quickly and safely as possible.|