-
Notifications
You must be signed in to change notification settings - Fork 429
docs(feature-flags): create concrete documentation #594
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 8 commits
faec4ce
c7bd7fb
9019f30
d1b7c22
5a3aa25
a691676
745ac9f
7a66dab
b34643d
e5a24fd
20cce82
527921e
85d2fc5
84f8bfd
0250511
5385b4f
d246f67
7c5a881
0f6a230
4a159ec
1c72a06
186293f
8a3ee9d
b8ee65f
4cb287b
1195f7c
48abcba
350abac
8466cf7
ee69581
b5e837e
7ff670d
642d0eb
1628b2a
f1e98ca
5567f6e
02c9169
58258cd
1dabcd9
dcbe08b
eb72d96
fec2a60
802aab3
203664c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,57 +1,263 @@ | ||
--- | ||
title: Feature flags | ||
description: Utility | ||
title: Feature flags description: Utility | ||
--- | ||
|
||
The feature flags utility provides a simple rule engine to define when one or multiple features should be enabled depending on the input. | ||
The feature flags utility provides a simple rule engine to define when one or multiple features should be enabled | ||
depending on the input. | ||
|
||
!!! tip "For simpler use cases where a feature is simply on or off for all users, use [Parameters](parameters.md) utility instead." | ||
!!! tip "For simpler use cases where a feature is simply on or off for all users, use [Parameters](parameters.md) | ||
utility instead." | ||
|
||
## Terminology | ||
|
||
Feature flags are used to modify a system behaviour without having to change their code. These flags can be static or dynamic. | ||
Feature flags are used to modify a system behaviour without having to change their code. These flags can be static or | ||
dynamic. | ||
|
||
**Static feature flags** are commonly used for long-lived behaviours that will rarely change, for example `TRACER_ENABLED=True`. These are better suited for [Parameters utility](parameters.md). | ||
**Static feature flags** are commonly used for long-lived behaviours that will rarely change, for | ||
example `TRACER_ENABLED=True`. These are better suited for [Parameters utility](parameters.md). | ||
|
||
**Dynamic feature flags** are typically used for experiments where you'd want to enable a feature for a limited set of customers, for example A/B testing and Canary releases. These are better suited for this utility, as you can create multiple conditions on whether a feature flag should be `True` or `False`. | ||
**Dynamic feature flags** are typically used for experiments where you'd want to enable a feature for a limited set of | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i dont think this is accurate. you can achieve the same thing with static flags. The dynamic part just allows you to change them faster without redeploying your service. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Even if we can redploy fast (enough), without rules the flags will have the same value in our code execution, it doesn't make them dynamic. I think we can't achieve dyamic behaivour, say A/B testing, by just redeploying static flags. |
||
customers, for example A/B testing and Canary releases. These are better suited for this utility, as you can create | ||
multiple conditions on whether a feature flag should be `True` or `False`. | ||
|
||
That being said, be mindful that feature flags can increase your application complexity over time if you're not careful; use them sparingly. | ||
That being said, be mindful that feature flags can increase your application complexity over time if you're not careful; | ||
use them sparingly. | ||
|
||
!!! tip "Read [this article](https://martinfowler.com/articles/feature-toggles.html){target="_blank"} for more details on different types of feature flags and trade-offs" | ||
!!! tip "Read [this article](https://martinfowler.com/articles/feature-toggles.html){target="_blank"} for more details | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. would appreciate a link to my original feature flags blog, but no pressure ;) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also a pretty good article https://www.atlassian.com/continuous-delivery/principles/feature-flags Although Martin Fowler's blog is very comprehensive. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. CloudBees have their own implementaiton: https://www.cloudbees.com/blog/ultimate-feature-flag-guide There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ha! I have stumbled upon all of the mentioned articles by now 😅, we can make a list |
||
on different types of feature flags and trade-offs" | ||
|
||
## Key features | ||
|
||
> TODO: Revisit once getting started and advanced sections are complete | ||
|
||
* Define simple feature flags to dynamically decide when to enable a feature | ||
* Fetch one or all feature flags enabled for a given application context | ||
* Bring your own configuration store | ||
|
||
## Getting started | ||
|
||
### Create a feature flag store | ||
|
||
By default, this utility provides AWS AppConfig as a configuration store. To create a dedicate you can use this | ||
cloudformation template: | ||
|
||
=== "template.yaml" | ||
|
||
```yaml | ||
AWSTemplateFormatVersion: "2010-09-09" | ||
Description: A sample template | ||
Resources: | ||
FeatureStoreApp: | ||
Type: AWS::AppConfig::Application | ||
Properties: | ||
Description: "AppConfig Appliction for feature toggles" | ||
Name: my-app | ||
|
||
FeatureStoreDevEnv: | ||
Type: AWS::AppConfig::Environment | ||
Properties: | ||
ApplicationId: !Ref FeatureStoreApp | ||
Description: "Development Environment for the App Config Store" | ||
Name: "development" | ||
|
||
FeatureStoreConfigProfile: | ||
Type: AWS::AppConfig::ConfigurationProfile | ||
Properties: | ||
ApplicationId: !Ref FeatureStoreApp | ||
Name: "MyTestProfile" | ||
LocationUri: "hosted" | ||
|
||
HostedConfigVersion: | ||
Type: AWS::AppConfig::HostedConfigurationVersion | ||
Properties: | ||
ApplicationId: !Ref FeatureStoreApp | ||
ConfigurationProfileId: !Ref FeatureStoreConfigProfile | ||
Description: 'A sample hosted configuration version' | ||
Content: | | ||
{ | ||
"premium_features": { | ||
"default": false, | ||
"rules": { | ||
"customer tier equals premium": { | ||
"when_match": true, | ||
"conditions": [ | ||
{ | ||
"action": "EQUALS", | ||
"key": "tier", | ||
"value": "premium" | ||
} | ||
] | ||
} | ||
} | ||
}, | ||
"feature2": { | ||
"default": true | ||
} | ||
} | ||
ContentType: 'application/json' | ||
|
||
ConfigDeployment: | ||
Type: AWS::AppConfig::Deployment | ||
Properties: | ||
ApplicationId: !Ref FeatureStoreApp | ||
ConfigurationProfileId: !Ref FeatureStoreConfigProfile | ||
ConfigurationVersion: !Ref HostedConfigVersion | ||
DeploymentStrategyId: "AppConfig.AllAtOnce" | ||
EnvironmentId: !Ref FeatureStoreDevEnv | ||
``` | ||
|
||
The `Content` parameter is a json structure of the feature flags and rules. | ||
|
||
### IAM Permissions | ||
|
||
By default, this utility provides AWS AppConfig as a configuration store. As such, you IAM Role needs permission - `appconfig:GetConfiguration` - to fetch feature flags from AppConfig. | ||
Because powertools needs to fetch the configuration from the AppConfig, you need to add `appconfig:GetConfiguration` | ||
action to your function. | ||
|
||
### Creating feature flags | ||
|
||
> NOTE: Explain schema, provide sample boto3 script and CFN to create one | ||
When using the feature flags utility powertools expects specific schema stored in your AppConfig configuration which | ||
incldues: | ||
|
||
* list of named features | ||
* default value | ||
* set of rules that powertools will evaluate | ||
|
||
Each rule should contain: | ||
|
||
* value if condition is met | ||
* list of conditions with `action`, `key` and `value` attributes. | ||
|
||
Here is small example of a premium feature with a default value `false` and one rule with a condition: if the passed | ||
context equals `{"tier": "premium"}` return true. | ||
|
||
```json | ||
{ | ||
"premium_feature": { | ||
"default": false, | ||
"rules": { | ||
"customer tier equals premium": { | ||
"when_match": true, | ||
"conditions": [ | ||
{ | ||
"action": "EQUALS", | ||
"key": "tier", | ||
"value": "premium" | ||
} | ||
] | ||
} | ||
} | ||
} | ||
} | ||
``` | ||
|
||
#### Rules | ||
|
||
The rules are evaluated based on conditions which have the structure: | ||
|
||
```json | ||
{ | ||
"action": "EQUALS", | ||
"key": "tier", | ||
"value": "premium" | ||
} | ||
``` | ||
|
||
The `action` configuration can have 4 different values: `EQUALS`, `STARTSWITH`, `ENDSWITH` and `CONTAINS`. If you have | ||
multiple rules powertools will evaluate every rule with a logical AND. | ||
|
||
### Setup a feature flag store | ||
|
||
First setup is to setup the `AppConfigStore` based on the AppConfig parameters you have created with the previous | ||
CloudFormation template. | ||
|
||
```python | ||
|
||
app_config = AppConfigStore( | ||
environment="FeatureStore", | ||
am29d marked this conversation as resolved.
Show resolved
Hide resolved
|
||
application="product-dev", | ||
name="features", | ||
cache_seconds=300 | ||
) | ||
|
||
``` | ||
|
||
### Fetching a single feature flag | ||
|
||
To fetch a single feature, setup the `FeatureFlags` instance and call the `evaluate` method. | ||
|
||
```python | ||
feature_flags = FeatureFlags(store=app_config) | ||
ctx = {"username": "lessa", "tier": "premium", "location": "NL"} | ||
|
||
has_premium_features: bool = feature_flags.evaluate(name="premium_features", | ||
context=ctx, | ||
default=False) | ||
``` | ||
|
||
The `context` parameter is optional and will be used for rule evaluation. In this case we have the `key` set | ||
as `username` and `value` set to `lessa`. Feature flag schema to match this could look like this: | ||
|
||
```json | ||
{ | ||
"premium_features": { | ||
"default": false, | ||
"rules": { | ||
"username is lessa and tier is premium": { | ||
"when_match": true, | ||
"conditions": [ | ||
{ | ||
"action": "EQUALS", | ||
"key": "username", | ||
"value": "lessa" | ||
}, | ||
{ | ||
"action": "EQUALS", | ||
"key": "tier", | ||
"value": "premium" | ||
} | ||
] | ||
} | ||
} | ||
} | ||
} | ||
``` | ||
|
||
|
||
### Fetching all feature flags | ||
In cases where you need to get a list of all the features that are enabled you can use `get_enabled_features` method: | ||
|
||
```python | ||
feature_flags = FeatureFlags(store=app_config) | ||
ctx = {"username": "lessa", "tier": "premium", "location": "NL"} | ||
|
||
all_features: list[str] = feature_flags.get_enabled_features(context=ctx) | ||
``` | ||
As a result you will get a list of all the names of the features from your feaute flag configuration. | ||
For example if you have two features with the following configuration and both are evaluated to `true`: | ||
|
||
```json hl_lines="2 6" | ||
{ | ||
"feature1": { | ||
"default": false, | ||
"rules": {...} | ||
}, | ||
"feature2": { | ||
"default": false, | ||
"rules": {...} | ||
}, | ||
... | ||
} | ||
} | ||
``` | ||
The response of `get_enabled_features` will be `["feautre1", "feature2"]`. | ||
|
||
|
||
### Advanced | ||
|
||
#### Adjusting cache TTL | ||
|
||
|
||
|
||
### Partially enabling features | ||
|
||
### Bring your own store provider | ||
|
||
## Testing your code | ||
|
||
> NOTE: Share example on how customers can unit test their feature flags |
Uh oh!
There was an error while loading. Please reload this page.