-
Notifications
You must be signed in to change notification settings - Fork 72
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: add feature-flagging and references (#936)
* adds "feature-flagging" section * rolls "OpenFeature Compliance" into this section... I think it makes sense here rather than on its own... I have another PR coming soon that will remove that page and do some related minor restructuring * makes distinction between custom operation configuration, and implementation --------- Signed-off-by: Todd Baert <[email protected]>
- Loading branch information
Showing
16 changed files
with
709 additions
and
52 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# Feature Flagging | ||
|
||
Feature flags are a software development technique that allows teams to enable, disable or change the behavior of certain features or code paths in a product or service, without modifying the source code. | ||
|
||
## OpenFeature Compliance | ||
|
||
[OpenFeature](https://openfeature.dev/) is an open standard that provides a vendor-agnostic, community-driven API for feature flagging. | ||
The flagd project is fully OpenFeature-compliant. | ||
In fact, flagd was initially conceived as a reference implementation for an OpenFeature backend, but has become a powerful tool in its own right. | ||
For this reason, you'll find flagd's concepts and terminology align with that of the OpenFeature project. | ||
Within the context of an OpenFeature-compliant feature flag solution, flagd artifacts and libraries comprise the [flag management system](https://openfeature.dev/specification/glossary#flag-management-system) and [providers](https://openfeature.dev/specification/glossary#provider). | ||
These artifacts and libraries alone won't allow you to evaluate flags in your application - you'll also need the [OpenFeature SDK](https://openfeature.dev/specification/glossary#feature-flag-sdk) for your language as well, which provides the evaluation API for application developers to use. | ||
|
||
## Supported Feature Flagging Use-Cases | ||
|
||
Below is a non-exhaustive table of common feature flag use-cases, and how flagd supports them: | ||
|
||
| Use case | flagd Feature | | ||
| ----------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| flag evaluation | Returns the value of a particular feature flag, if the flag is enabled. Supports flags of various types including boolean, numeric, string, and JSON. | | ||
| dynamic configuration | Flag definitions from any sync source are monitored for changes, with some syncs supporting near real time updates. | | ||
| dynamic (context-sensitive) evaluation | flagd evaluations are context sensitive. Rules can use arbitrary context attributes as inputs for flag evaluation logic. | | ||
| fractional evaluation / random assignment | flagd's [fractional](../reference/custom-operations/fractional-operation.md) custom operation supports pseudorandom assignment of flag values. | | ||
| progressive roll-outs | Progressive roll-outs of new features can be accomplished by leveraging the [fractional](../reference/custom-operations/fractional-operation.md) custom operation as well as automation in your build pipeline, SCM, or infrastructure which updates the distribution over time. | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
138 changes: 138 additions & 0 deletions
138
web-docs/reference/custom-operations/fractional-operation.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
# Fractional Operation | ||
|
||
OpenFeature allows clients to pass contextual information which can then be used during a flag evaluation. For example, a client could pass the email address of the user. | ||
|
||
```js | ||
// Factional evaluation property name used in a targeting rule | ||
"fractional": [ | ||
// Evaluation context property used to determine the split | ||
{ "var": "email" }, | ||
// Split definitions contain an array with a variant and percentage | ||
// Percentages must add up to 100 | ||
[ | ||
// Must match a variant defined in the flag definition | ||
"red", | ||
// The probability this variant is selected | ||
50 | ||
], | ||
[ | ||
// Must match a variant defined in the flag definition | ||
"green", | ||
// The probability this variant is selected | ||
50 | ||
] | ||
] | ||
``` | ||
|
||
See the [headerColor](https://github.com/open-feature/flagd/blob/main/samples/example_flags.flagd.json#L88-#L133) flag. | ||
The `defaultVariant` is `red`, but it contains a [targeting rule](reusable_targeting_rules.md), meaning a fractional evaluation occurs for flag evaluation with a `context` object containing `email` and where that `email` value contains `@faas.com`. | ||
|
||
In this case, `25%` of the evaluations will receive `red`, `25%` will receive `blue`, and so on. | ||
|
||
Assignment is deterministic (sticky) based on the expression supplied as the first parameter (`{ "var": "email" }`, in this case). | ||
The value retrieved by this expression is referred to as the "bucketing value". | ||
The bucketing value expression can be omitted, in which case a concatenation of the `targetingKey` and the `flagKey` will be used. | ||
|
||
The `fractional` operation is a custom JsonLogic operation which deterministically selects a variant based on | ||
the defined distribution of each variant (as a percentage). | ||
This works by hashing ([murmur3](https://github.com/aappleby/smhasher/blob/master/src/MurmurHash3.cpp)) | ||
the given data point, converting it into an int in the range [0, 99]. | ||
Whichever range this int falls in decides which variant | ||
is selected. | ||
As hashing is deterministic we can be sure to get the same result every time for the same data point. | ||
|
||
The `fractional` operation can be added as part of a targeting definition. | ||
The value is an array and the first element is the name of the property to use from the evaluation context. | ||
This value should typically be something that remains consistent for the duration of a users session (e.g. email or session ID). | ||
The other elements in the array are nested arrays with the first element representing a variant and the second being the percentage that this option is selected. | ||
There is no limit to the number of elements but the configured percentages must add up to 100. | ||
|
||
## Example | ||
|
||
Flags defined as such: | ||
|
||
```json | ||
{ | ||
"flags": { | ||
"headerColor": { | ||
"variants": { | ||
"red": "#FF0000", | ||
"blue": "#0000FF", | ||
"green": "#00FF00" | ||
}, | ||
"defaultVariant": "red", | ||
"state": "ENABLED", | ||
"targeting": { | ||
"fractional": [ | ||
{ "var": "email" }, | ||
[ | ||
"red", | ||
50 | ||
], | ||
[ | ||
"blue", | ||
20 | ||
], | ||
[ | ||
"green", | ||
30 | ||
] | ||
] | ||
} | ||
} | ||
} | ||
} | ||
``` | ||
|
||
will return variant `red` 50% of the time, `blue` 20% of the time & `green` 30% of the time. | ||
|
||
Command: | ||
|
||
```shell | ||
curl -X POST "localhost:8013/schema.v1.Service/ResolveString" -d '{"flagKey":"headerColor","context":{"email": "[email protected]"}}' -H "Content-Type: application/json" | ||
``` | ||
|
||
Result: | ||
|
||
```shell | ||
{"value":"#0000FF","reason":"TARGETING_MATCH","variant":"blue"} | ||
``` | ||
|
||
Command: | ||
|
||
```shell | ||
curl -X POST "localhost:8013/schema.v1.Service/ResolveString" -d '{"flagKey":"headerColor","context":{"email": "[email protected]"}}' -H "Content-Type: application/json" | ||
``` | ||
|
||
Result: | ||
|
||
```json | ||
{"value":"#00FF00","reason":"TARGETING_MATCH","variant":"green"} | ||
``` | ||
|
||
Notice that rerunning either curl command will always return the same variant and value. | ||
The only way to get a different value is to change the email or update the `fractional` configuration. | ||
|
||
### Migrating from legacy "fractionalEvaluation" | ||
|
||
If you are using a legacy fractional evaluation (`fractionalEvaluation`), it's recommended you migrate to `fractional`. | ||
The new `fractional` evaluator supports nested properties and JsonLogic expressions. | ||
To migrate, simply use a JsonLogic variable declaration for the bucketing property, instead of a string: | ||
|
||
old: | ||
|
||
```json | ||
"fractionalEvaluation": [ | ||
"email", | ||
[ "red", 25 ], [ "blue", 25 ], [ "green", 25 ], [ "yellow", 25 ] | ||
] | ||
``` | ||
|
||
new: | ||
|
||
```json | ||
"fractional": [ | ||
{ "var": "email" }, | ||
[ "red", 25 ], [ "blue", 25 ], [ "green", 25 ], [ "yellow", 25 ] | ||
] | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
# Semantic Version Operation | ||
|
||
OpenFeature allows clients to pass contextual information which can then be used during a flag evaluation. For example, a client could pass the email address of the user. | ||
|
||
In some scenarios, it is desirable to use that contextual information to segment the user population further and thus return dynamic values. | ||
|
||
The `sem_ver` evaluation checks if the given property matches a semantic versioning condition. | ||
It returns 'true', if the value of the given property meets the condition, 'false' if not. | ||
Note that the 'sem_ver' evaluation rule must contain exactly three items: | ||
|
||
1. Target property: this needs which both resolve to a semantic versioning string | ||
2. Operator: One of the following: `=`, `!=`, `>`, `<`, `>=`, `<=`, `~` (match minor version), `^` (match major version) | ||
3. Target value: this needs which both resolve to a semantic versioning string | ||
|
||
The `sem_ver` evaluation returns a boolean, indicating whether the condition has been met. | ||
|
||
```js | ||
{ | ||
"if": [ | ||
{ | ||
"sem_ver": [{"var": "version"}, ">=", "1.0.0"] | ||
}, | ||
"red", null | ||
] | ||
} | ||
``` | ||
|
||
## Example for 'sem_ver' Evaluation | ||
|
||
Flags defined as such: | ||
|
||
```json | ||
{ | ||
"flags": { | ||
"headerColor": { | ||
"variants": { | ||
"red": "#FF0000", | ||
"blue": "#0000FF", | ||
"green": "#00FF00" | ||
}, | ||
"defaultVariant": "blue", | ||
"state": "ENABLED", | ||
"targeting": { | ||
"if": [ | ||
{ | ||
"sem_ver": [{"var": "version"}, ">=", "1.0.0"] | ||
}, | ||
"red", "green" | ||
] | ||
} | ||
} | ||
} | ||
} | ||
``` | ||
|
||
will return variant `red`, if the value of the `version` is a semantic version that is greater than or equal to `1.0.0`. | ||
|
||
Command: | ||
|
||
```shell | ||
curl -X POST "localhost:8013/schema.v1.Service/ResolveString" -d '{"flagKey":"headerColor","context":{"version": "1.0.1"}}' -H "Content-Type: application/json" | ||
``` | ||
|
||
Result: | ||
|
||
```json | ||
{"value":"#00FF00","reason":"TARGETING_MATCH","variant":"red"} | ||
``` | ||
|
||
Command: | ||
|
||
```shell | ||
curl -X POST "localhost:8013/schema.v1.Service/ResolveString" -d '{"flagKey":"headerColor","context":{"version": "0.1.0"}}' -H "Content-Type: application/json" | ||
``` | ||
|
||
Result: | ||
|
||
```shell | ||
{"value":"#0000FF","reason":"TARGETING_MATCH","variant":"green"} | ||
``` |
Oops, something went wrong.