-
Notifications
You must be signed in to change notification settings - Fork 127
Update README to mention the usage of feature-based injection (variant service) #388
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 7 commits
7367e97
8db8bb4
4820427
18ba831
4febe1a
efa42dd
80d2817
c5fb3d7
a902b98
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 | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -36,6 +36,7 @@ Here are some of the benefits of using this library: | |||||||||
| * [Targeting](#targeting) | ||||||||||
| * [Targeting Exclusion](#targeting-exclusion) | ||||||||||
| * [Variants](#variants) | ||||||||||
| * [Variants in Dependency Injection](#variants-in-dependency-injection) | ||||||||||
| * [Telemetry](#telemetry) | ||||||||||
| * [Enabling Telemetry](#enabling-telemetry) | ||||||||||
| * [Custom Telemetry Publishers](#custom-telemetry-publishers) | ||||||||||
|
|
@@ -924,7 +925,7 @@ The `Allocation` setting of a feature flag has the following properties: | |||||||||
| | `DefaultWhenDisabled` | Specifies which variant should be used when a variant is requested while the feature is considered disabled. | | ||||||||||
| | `DefaultWhenEnabled` | Specifies which variant should be used when a variant is requested while the feature is considered enabled and no other variant was assigned to the user. | | ||||||||||
| | `User` | Specifies a variant and a list of users to whom that variant should be assigned. | | ||||||||||
| | `Group` | Specifies a variant and a list of groups the current user has to be in for that variant to be assigned. | | ||||||||||
| | `Group` | Specifies a variant and a list of groups. The variant will be assigned if the user is in at least one of the groups. | | ||||||||||
| | `Percentile` | Specifies a variant and a percentage range the user's calculated percentage has to fit into for that variant to be assigned. | | ||||||||||
| | `Seed` | The value which percentage calculations for `Percentile` are based on. The percentage calculation for a specific user will be the same across all features if the same `Seed` value is used. If no `Seed` is specified, then a default seed is created based on the feature name. | | ||||||||||
|
|
||||||||||
|
|
@@ -934,7 +935,9 @@ If the feature is enabled, the feature manager will check the `User`, `Group`, a | |||||||||
|
|
||||||||||
| Allocation logic is similar to the [Microsoft.Targeting](./README.md#MicrosoftTargeting) feature filter, but there are some parameters that are present in targeting that aren't in allocation, and vice versa. The outcomes of targeting and allocation are not related. | ||||||||||
|
|
||||||||||
| #### Overriding Enabled State with a Variant | ||||||||||
| **Note:** To allow allocating feature variants, you need to register `ITargetingContextAccessor`. This could be done by calling `WithTargeting<T>` method. | ||||||||||
|
zhiyuanliang-ms marked this conversation as resolved.
Outdated
|
||||||||||
|
|
||||||||||
| ### Overriding Enabled State with a Variant | ||||||||||
|
|
||||||||||
| You can use variants to override the enabled state of a feature flag. This gives variants an opportunity to extend the evaluation of a feature flag. If a caller is checking whether a flag that has variants is enabled, the feature manager will check if the variant assigned to the current user is set up to override the result. This is done using the optional variant property `StatusOverride`. By default, this property is set to `None`, which means the variant doesn't affect whether the flag is considered enabled or disabled. Setting `StatusOverride` to `Enabled` allows the variant, when chosen, to override a flag to be enabled. Setting `StatusOverride` to `Disabled` provides the opposite functionality, therefore disabling the flag when the variant is chosen. A feature with a `Status` of `Disabled` cannot be overridden. | ||||||||||
|
Contributor
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. Maybe we should add a "why?" here, because there's only a narrow reason they would want to use the overrides. It's if a customer wants to allocate via variants without changing their existing IsEnabled code. Meaning they want to return bool results but have more than 2 "buckets".
Member
Author
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.
quoted from the design doc This is the original purpose for this design.
I think this sentence is a solid reason but we may come up a good story or an attracting use case of statusOverride.
Contributor
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.
This part is valid, but it's still not a big use case. Essentially, customers can always use a normal flag with filters to achieve whatever boolean targeting they want to achieve. Variants don't offer an advantage to boolean targeting over the standard TargetingFilter. One reason someone would use Variants in the bool world is to adding more telemetry "buckets" so they can split their traffic (although this is also not necessary as the split traffic of "true" results should be equal). Another reason is if a customer's plan is to call both GetVariant and IsEnabled(like using FeatureGateAttribute) on a single flag, then they might use it, but this is likely overloading what a flag should be in charge of. My fear is that users will see this section in the readme and think that they should be using it- instead of using it to address a specific problem. |
||||||||||
|
|
||||||||||
|
|
@@ -970,6 +973,57 @@ If you are using a feature flag with binary variants, the `StatusOverride` prope | |||||||||
|
|
||||||||||
| In the above example, the feature is enabled by the `AlwaysOn` filter. If the current user is in the calculated percentile range of 10 to 20, then the `On` variant is returned. Otherwise, the `Off` variant is returned and because `StatusOverride` is equal to `Disabled`, the feature will now be considered disabled. | ||||||||||
|
|
||||||||||
| ## Variants in Dependency Injection | ||||||||||
|
zhiyuanliang-ms marked this conversation as resolved.
Outdated
|
||||||||||
|
|
||||||||||
| Dependency injection can be wired up with a variant feature flag. You can use a variant feature flag to control which implementation of a service should be used by the dependency injection, based on the allocated variant of the feature flag. This could be done by using `IVariantServiceProvider<TService>`. | ||||||||||
|
zhiyuanliang-ms marked this conversation as resolved.
Outdated
|
||||||||||
|
|
||||||||||
| ``` C# | ||||||||||
| IVariantServiceProvider<IAlgorithm> algorithmServiceProvider; | ||||||||||
| ... | ||||||||||
|
|
||||||||||
| IAlgorithm forecastAlgorithm = await algorithmServiceProvider.GetServiceAsync(cancellationToken); | ||||||||||
| ``` | ||||||||||
|
|
||||||||||
| The `IVaraintServiceProvider<IAlgorithm>` will retrieve a specific implementation of `IAlgorithm` from the dependency injection container. It can be registered by calling `WithVariantService<TService>` on the `IFeatureManagementBuilder`. | ||||||||||
|
zhiyuanliang-ms marked this conversation as resolved.
Outdated
|
||||||||||
|
|
||||||||||
| ``` C# | ||||||||||
| services.AddFeatureManagement() | ||||||||||
| .WithVariantService<IAlgorithm>("ForecastAlgorithm"); | ||||||||||
| ``` | ||||||||||
|
|
||||||||||
| With the call above, `IAlgorithm` will be wired up with the variant feature flag `ForecastAlgorithm`. The `GetServiceAsync` method of `IVariantService<IAlgorithm>` will retrieve the variant service of `IAlgorithm` which matches the name of allocated variant of the `ForecastAlgorithm` flag, from the dependency injection container. | ||||||||||
|
|
||||||||||
| ``` javascript | ||||||||||
| { | ||||||||||
| "ForecastAlgorithm": { | ||||||||||
| "Variants": [ | ||||||||||
| { | ||||||||||
| "Name": "AlgorithmBeta" | ||||||||||
| }, | ||||||||||
| ... | ||||||||||
| ] | ||||||||||
| } | ||||||||||
| } | ||||||||||
| ``` | ||||||||||
|
|
||||||||||
| **Note:** The `WithvariantService<TService>` method will not register any implementation of `TService`. You need to register variant serices as `TService` to allow `IVariantServiceProvider<TService>` to retrieve them from the dependency injection container. Which extension method to use for registration depends on your needs. Here is an example. | ||||||||||
|
zhiyuanliang-ms marked this conversation as resolved.
Outdated
|
||||||||||
|
|
||||||||||
| ``` C# | ||||||||||
| services.AddSingleton<IAlgorithm, AlgorithmBeta>(); | ||||||||||
|
Member
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.
Suggested change
Member
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. What happens if we forget to register implementation for the service?
Member
Author
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. It will return null if there is no matched implementation found in the DI container.
Member
Author
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. How about adding an sentence to mention this after the section Something like: services.AddFeatureManagement()
.WithVariantService<IAlgorithm>("ForecastAlgorithm");With the call above,
Member
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. How about The call above makes |
||||||||||
| ``` | ||||||||||
|
|
||||||||||
| #### Variant Service Alias Attribute | ||||||||||
|
|
||||||||||
| ``` C# | ||||||||||
| [VariantServiceAlias("Beta")] | ||||||||||
| public class AlgorithmBeta : IAlgorithm | ||||||||||
| { | ||||||||||
| ... | ||||||||||
| } | ||||||||||
| ``` | ||||||||||
|
|
||||||||||
| The variant service provider will use the type names of implementations to match the allocated variant. If a variant service is decorated with the `VariantServiceAliasAttribute`, the name declared in this attribute should be used in configuration to reference this variant service. | ||||||||||
|
|
||||||||||
| ## Telemetry | ||||||||||
|
|
||||||||||
| When a feature flag change is deployed, it is often important to analyze its effect on an application. For example, here are a few questions that may arise: | ||||||||||
|
|
||||||||||
Uh oh!
There was an error while loading. Please reload this page.