From 8e914b9f935a755ada559377d78e40bd414f5108 Mon Sep 17 00:00:00 2001 From: AMER JUSUPOVIC Date: Fri, 8 Dec 2023 13:54:02 -0800 Subject: [PATCH 01/14] mention itargetingcontextaccessor for variant allocation --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7556def1..3ff76904 100644 --- a/README.md +++ b/README.md @@ -767,7 +767,7 @@ In the above example, if the feature is not enabled, `GetVariantAsync` would ret If the feature is enabled, the feature manager will check the `User`, `Group`, and `Percentile` allocations in that order to allocate a variant for this feature. If the user being evaluated is named `Marsha`, in the group named `Ring1`, or the user happens to fall between the 0 and 10th percentile calculated with the given `Seed`, then the specified variant is returned for that allocation. In this case, all of these would return the `Big` variant. If none of these allocations match, the `DefaultWhenEnabled` variant is returned, which is `Small`. -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. +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. Like targeting, allocation gets user information from `ITargetingContextAccessor`, but the outcomes of targeting and allocation are not related. ### Overriding Enabled State with a Variant From b3f1874876bd05ee83d7a1cbb4cd6da1ac25d756 Mon Sep 17 00:00:00 2001 From: AMER JUSUPOVIC Date: Tue, 12 Dec 2023 14:55:33 -0800 Subject: [PATCH 02/14] update changes --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3ff76904..ba3a1aba 100644 --- a/README.md +++ b/README.md @@ -583,7 +583,7 @@ services.AddFeatureManagement(); #### ITargetingContextAccessor -To use the `TargetingFilter` in a web application an implementation of `ITargetingContextAccessor` is required. This is because when a targeting evaluation is being performed information such as what user is currently being evaluated is needed. This information is known as the targeting context. Different web applications may extract this information from different places. Some common examples of where an application may pull the targeting context are the request's HTTP context or a database. +To use the `TargetingFilter` or the `Allocation` property in a web application, an implementation of `ITargetingContextAccessor` is required. This is because when a targeting evaluation or variant assignment is being performed, information such as what user is currently being evaluated is needed. This information is known as the targeting context. Different web applications may extract this information from different places. Some common examples of where an application may pull the targeting context are the request's HTTP context or a database. An example that extracts targeting context information from the application's HTTP context is included in the [FeatureFlagDemo](./examples/FeatureFlagDemo/HttpContextTargetingContextAccessor.cs) example project. This method relies on the use of `IHttpContextAccessor` which is discussed [here](./README.md#Using-HttpContext). @@ -767,7 +767,7 @@ In the above example, if the feature is not enabled, `GetVariantAsync` would ret If the feature is enabled, the feature manager will check the `User`, `Group`, and `Percentile` allocations in that order to allocate a variant for this feature. If the user being evaluated is named `Marsha`, in the group named `Ring1`, or the user happens to fall between the 0 and 10th percentile calculated with the given `Seed`, then the specified variant is returned for that allocation. In this case, all of these would return the `Big` variant. If none of these allocations match, the `DefaultWhenEnabled` variant is returned, which is `Small`. -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. Like targeting, allocation gets user information from `ITargetingContextAccessor`, but the outcomes of targeting and allocation are not related. +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. Like targeting, allocation can only access user information once an implementation of `ITargetingContextAccessor` has been added to the service collection. The outcomes of targeting and allocation are not related. ### Overriding Enabled State with a Variant From d429d778cfa8225c77ef76368faac03a7ae4af46 Mon Sep 17 00:00:00 2001 From: AMER JUSUPOVIC Date: Tue, 12 Dec 2023 15:05:52 -0800 Subject: [PATCH 03/14] add reference to ITargetingContextAccessor to readme for allocation --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ba3a1aba..f87f1909 100644 --- a/README.md +++ b/README.md @@ -583,7 +583,7 @@ services.AddFeatureManagement(); #### ITargetingContextAccessor -To use the `TargetingFilter` or the `Allocation` property in a web application, an implementation of `ITargetingContextAccessor` is required. This is because when a targeting evaluation or variant assignment is being performed, information such as what user is currently being evaluated is needed. This information is known as the targeting context. Different web applications may extract this information from different places. Some common examples of where an application may pull the targeting context are the request's HTTP context or a database. +To use the `TargetingFilter` in a web application, an implementation of `ITargetingContextAccessor` is required. This is because when a targeting evaluation is being performed, information such as what user is currently being evaluated is needed. This information is known as the targeting context. Different web applications may extract this information from different places. Some common examples of where an application may pull the targeting context are the request's HTTP context or a database. An example that extracts targeting context information from the application's HTTP context is included in the [FeatureFlagDemo](./examples/FeatureFlagDemo/HttpContextTargetingContextAccessor.cs) example project. This method relies on the use of `IHttpContextAccessor` which is discussed [here](./README.md#Using-HttpContext). @@ -767,7 +767,7 @@ In the above example, if the feature is not enabled, `GetVariantAsync` would ret If the feature is enabled, the feature manager will check the `User`, `Group`, and `Percentile` allocations in that order to allocate a variant for this feature. If the user being evaluated is named `Marsha`, in the group named `Ring1`, or the user happens to fall between the 0 and 10th percentile calculated with the given `Seed`, then the specified variant is returned for that allocation. In this case, all of these would return the `Big` variant. If none of these allocations match, the `DefaultWhenEnabled` variant is returned, which is `Small`. -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. Like targeting, allocation can only access user information once an implementation of `ITargetingContextAccessor` has been added to the service collection. The outcomes of targeting and allocation are not related. +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. Like targeting, allocation can only access user information once an implementation of `ITargetingContextAccessor` has been added to the service collection. Without this service, allocation can only return default variants if they're specified. The outcomes of targeting and allocation are not related. ### Overriding Enabled State with a Variant From 37353664147de9ed0447653d29673c8673ba9d14 Mon Sep 17 00:00:00 2001 From: AMER JUSUPOVIC Date: Thu, 14 Dec 2023 16:58:12 -0800 Subject: [PATCH 04/14] update with new discussed changes, rename sections and introduce context sooner --- README.md | 57 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 61c8175c..0ac814ba 100644 --- a/README.md +++ b/README.md @@ -703,7 +703,7 @@ In the above example, the feature will be enabled for users named `Jeff` and `Al When new features are added to an application, there may come a time when a feature has multiple different proposed design options. A common solution for deciding on a design is some form of A/B testing, which involves providing a different version of the feature to different segments of the user base and choosing a version based on user interaction. In this library, this functionality is enabled by representing different configurations of a feature with variants. -Variants enable a feature flag to become more than a simple on/off flag. A variant represents a value of a feature flag that can be a string, a number, a boolean, or even a configuration object. A feature flag that declares variants should define under what circumstances each variant should be used, which is covered in greater detail in the [Allocating a Variant](./README.md#allocating-a-variant) section. +Variants enable a feature flag to become more than a simple on/off flag. A variant represents a value of a feature flag that can be a string, a number, a boolean, or even a configuration object. A feature flag that declares variants should define under what circumstances each variant should be used, which is covered in greater detail in the [Allocating a Feature's Variants](./README.md#allocating-a-features-variants) section. ``` C# public class Variant @@ -720,9 +720,11 @@ public class Variant } ``` -### Getting a Feature's Variant +### Getting Variants -A feature's variant can be retrieved using the `IVariantFeatureManager`'s `GetVariantAsync` method. +For each feature, a variant can be retrieved using the `IVariantFeatureManager`'s `GetVariantAsync` method. The variant returned is dependent on the +user currently being evaluated, and that information is obtained from an instance of `TargetingContext`. This context can either be passed in when +calling `GetVariantAsync` or it can be automatically retrieved from an implementation of `ITargetingContextAccessor` if one is registered. ``` C# … @@ -735,28 +737,43 @@ IConfigurationSection variantConfiguration = variant.Configuration; // Do something with the resulting variant and its configuration ``` -### Setting a Variant's Configuration +### Defining a Feature's Variants -For each of the variants in the `Variants` property of a feature, there is a specified configuration. This can be set using either the `ConfigurationReference` or `ConfigurationValue` properties. `ConfigurationReference` is a string path that references a section of the current configuration that contains the feature flag declaration. `ConfigurationValue` is an inline configuration that can be a string, number, boolean, or configuration object. If both are specified, `ConfigurationValue` is used. If neither are specified, the returned variant's `Configuration` property will be null. +Each variant has two properties: a name and a configuration. The name is used to refer to a specific variant, and the configuration is the value of that variant. The configuration can be set using either the `ConfigurationReference` or `ConfigurationValue` properties. `ConfigurationReference` is a string path that references a section of the current configuration that contains the feature flag declaration. `ConfigurationValue` is an inline configuration that can be a string, number, boolean, or configuration object. If both are specified, `ConfigurationValue` is used. If neither are specified, the returned variant's `Configuration` property will be null. + +A list of all possible variants is defined for each feature under the `Variants` property. ``` -"Variants": [ - { - "Name": "Big", - "ConfigurationReference": "ShoppingCart:Big" - }, - { - "Name": "Small", - "ConfigurationValue": { - "Size": 300 +{ + "FeatureManagement": + { + "MyFlag": + { + "Variants": [ + { + "Name": "Big", + "ConfigurationReference": "ShoppingCart:Big" + }, + { + "Name": "Small", + "ConfigurationValue": { + "Size": 300 + } + } + ], + "EnabledFor": [ + { + "Name": "AlwaysOn" + } + ] } - } -] + } +} ``` -### Allocating a Variant +### Allocating a Feature's Variants -The process of allocating a variant to a specific feature is determined by the `Allocation` property of the feature. +The process of allocating a feature's variants is determined by the `Allocation` property of the feature. ``` "Allocation": { @@ -804,7 +821,7 @@ The `Allocation` setting of a feature flag has the following properties: | Property | Description | | ---------------- | ---------------- | | `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 variant was allocated to the user. | +| `DefaultWhenEnabled` | Specifies which variant should be used when a variant is requested while the feature is considered enabled and no other variant was allocated to the user. | | `User` | Specifies a variant and a list of users for which that variant should be used. | | `Group` | Specifies a variant and a list of groups the current user has to be in for that variant to be used. | | `Percentile` | Specifies a variant and a percentage range the user's calculated percentage has to fit into for that variant to be used. | @@ -814,7 +831,7 @@ In the above example, if the feature is not enabled, `GetVariantAsync` would ret If the feature is enabled, the feature manager will check the `User`, `Group`, and `Percentile` allocations in that order to allocate a variant for this feature. If the user being evaluated is named `Marsha`, in the group named `Ring1`, or the user happens to fall between the 0 and 10th percentile calculated with the given `Seed`, then the specified variant is returned for that allocation. In this case, all of these would return the `Big` variant. If none of these allocations match, the `DefaultWhenEnabled` variant is returned, which is `Small`. -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. Like targeting, allocation can only access user information once an implementation of `ITargetingContextAccessor` has been added to the service collection. Without this service, allocation can only return default variants if they're specified. The outcomes of targeting and allocation are not related. +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 From 26db004929f53a818bed1efd93c756edca850097 Mon Sep 17 00:00:00 2001 From: AMER JUSUPOVIC Date: Thu, 14 Dec 2023 17:01:01 -0800 Subject: [PATCH 05/14] fix wording of default --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0ac814ba..078c446a 100644 --- a/README.md +++ b/README.md @@ -821,7 +821,7 @@ The `Allocation` setting of a feature flag has the following properties: | Property | Description | | ---------------- | ---------------- | | `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 allocated to the user. | +| `DefaultWhenEnabled` | Specifies which variant should be used when a variant is requested while the feature is considered enabled and no other variant was allocated for the user. | | `User` | Specifies a variant and a list of users for which that variant should be used. | | `Group` | Specifies a variant and a list of groups the current user has to be in for that variant to be used. | | `Percentile` | Specifies a variant and a percentage range the user's calculated percentage has to fit into for that variant to be used. | From 52d7e2b255a574b02271aca638745bc63f35d6c8 Mon Sep 17 00:00:00 2001 From: AMER JUSUPOVIC Date: Thu, 14 Dec 2023 17:06:20 -0800 Subject: [PATCH 06/14] fix wording to avoid implying variants are assigned per feature --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 078c446a..098ff671 100644 --- a/README.md +++ b/README.md @@ -829,7 +829,7 @@ The `Allocation` setting of a feature flag has the following properties: In the above example, if the feature is not enabled, `GetVariantAsync` would return the variant allocated by `DefaultWhenDisabled`, which is `Small` in this case. -If the feature is enabled, the feature manager will check the `User`, `Group`, and `Percentile` allocations in that order to allocate a variant for this feature. If the user being evaluated is named `Marsha`, in the group named `Ring1`, or the user happens to fall between the 0 and 10th percentile calculated with the given `Seed`, then the specified variant is returned for that allocation. In this case, all of these would return the `Big` variant. If none of these allocations match, the `DefaultWhenEnabled` variant is returned, which is `Small`. +If the feature is enabled, the feature manager will check the `User`, `Group`, and `Percentile` allocations in that order to return a variant based on the current user. If the user being evaluated is named `Marsha`, in the group named `Ring1`, or the user happens to fall between the 0 and 10th percentile calculated with the given `Seed`, then the specified variant is returned for that allocation. In this case, all of these would return the `Big` variant. If none of these allocations match, the `DefaultWhenEnabled` variant is returned, which is `Small`. 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. From 3d9e71a66a6906c4e5ad427b0f548eb22f05da4b Mon Sep 17 00:00:00 2001 From: AMER JUSUPOVIC Date: Mon, 18 Dec 2023 14:22:12 -0800 Subject: [PATCH 07/14] use the term assign when referring to variants returned for a user --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 098ff671..b2ddf8ed 100644 --- a/README.md +++ b/README.md @@ -821,7 +821,7 @@ The `Allocation` setting of a feature flag has the following properties: | Property | Description | | ---------------- | ---------------- | | `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 allocated for the user. | +| `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 for which that variant should be used. | | `Group` | Specifies a variant and a list of groups the current user has to be in for that variant to be used. | | `Percentile` | Specifies a variant and a percentage range the user's calculated percentage has to fit into for that variant to be used. | @@ -829,13 +829,13 @@ The `Allocation` setting of a feature flag has the following properties: In the above example, if the feature is not enabled, `GetVariantAsync` would return the variant allocated by `DefaultWhenDisabled`, which is `Small` in this case. -If the feature is enabled, the feature manager will check the `User`, `Group`, and `Percentile` allocations in that order to return a variant based on the current user. If the user being evaluated is named `Marsha`, in the group named `Ring1`, or the user happens to fall between the 0 and 10th percentile calculated with the given `Seed`, then the specified variant is returned for that allocation. In this case, all of these would return the `Big` variant. If none of these allocations match, the `DefaultWhenEnabled` variant is returned, which is `Small`. +If the feature is enabled, the feature manager will check the `User`, `Group`, and `Percentile` allocations in that order to assign a variant to the current user. If the user being evaluated is named `Marsha`, in the group named `Ring1`, or the user happens to fall between the 0 and 10th percentile calculated with the given `Seed`, then the specified variant is returned for that allocation. In this case, all of these would return the `Big` variant. If none of these allocations match, the `DefaultWhenEnabled` variant is returned, which is `Small`. 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 -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, then variant allocation will be performed to see if an allocated variant 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. +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, then 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. If you are using a feature flag with binary variants, the `StatusOverride` property can be very helpful. It allows you to continue using APIs like `IsEnabledAsync` and `FeatureGateAttribute` in your application, all while benefiting from the new features that come with variants, such as percentile allocation and seed. From c226638aae4886755003c981c460e396f6882d88 Mon Sep 17 00:00:00 2001 From: AMER JUSUPOVIC Date: Mon, 18 Dec 2023 14:34:10 -0800 Subject: [PATCH 08/14] use assign term in more places --- README.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index b2ddf8ed..2eacf198 100644 --- a/README.md +++ b/README.md @@ -822,14 +822,16 @@ 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 for which that variant should be used. | -| `Group` | Specifies a variant and a list of groups the current user has to be in for that variant to be used. | -| `Percentile` | Specifies a variant and a percentage range the user's calculated percentage has to fit into for that variant to be used. | +| `User` | Specifies a variant and a list of users for which 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. | +| `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. | -In the above example, if the feature is not enabled, `GetVariantAsync` would return the variant allocated by `DefaultWhenDisabled`, which is `Small` in this case. +In the above example, if the feature is not enabled, the feature manager will assign the variant allocated by `DefaultWhenDisabled` to the current user, which is `Small` in this case. -If the feature is enabled, the feature manager will check the `User`, `Group`, and `Percentile` allocations in that order to assign a variant to the current user. If the user being evaluated is named `Marsha`, in the group named `Ring1`, or the user happens to fall between the 0 and 10th percentile calculated with the given `Seed`, then the specified variant is returned for that allocation. In this case, all of these would return the `Big` variant. If none of these allocations match, the `DefaultWhenEnabled` variant is returned, which is `Small`. +If the feature is enabled, the feature manager will check the `User`, `Group`, and `Percentile` allocations in that order to assign a variant. If the user being evaluated is named `Marsha`, in the group named `Ring1`, or the user happens to fall between the 0 and 10th percentile calculated with the given `Seed`, then the specified variant is assigned to the user. In this case, all of these would return the `Big` variant. If none of these allocations match, the user is assigned the `DefaultWhenEnabled` variant, which is `Small`. + +In either scenario, calling `GetVariantAsync` will return the variant that was assigned to the current user. 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. From df3eb50bf42be5d5a202435cbf54eb7bf7808d00 Mon Sep 17 00:00:00 2001 From: AMER JUSUPOVIC Date: Mon, 18 Dec 2023 14:44:35 -0800 Subject: [PATCH 09/14] small changes --- README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 2eacf198..5a2ea9e4 100644 --- a/README.md +++ b/README.md @@ -822,7 +822,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 for which that variant should be assigned. | +| `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. | | `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. | @@ -831,13 +831,11 @@ In the above example, if the feature is not enabled, the feature manager will as If the feature is enabled, the feature manager will check the `User`, `Group`, and `Percentile` allocations in that order to assign a variant. If the user being evaluated is named `Marsha`, in the group named `Ring1`, or the user happens to fall between the 0 and 10th percentile calculated with the given `Seed`, then the specified variant is assigned to the user. In this case, all of these would return the `Big` variant. If none of these allocations match, the user is assigned the `DefaultWhenEnabled` variant, which is `Small`. -In either scenario, calling `GetVariantAsync` will return the variant that was assigned to the current user. - 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 -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, then 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. +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. If you are using a feature flag with binary variants, the `StatusOverride` property can be very helpful. It allows you to continue using APIs like `IsEnabledAsync` and `FeatureGateAttribute` in your application, all while benefiting from the new features that come with variants, such as percentile allocation and seed. From ed32a956ec5f1ade6fb0ddb48dcb3aeab5807832 Mon Sep 17 00:00:00 2001 From: Amer Jusupovic <32405726+amerjusupovic@users.noreply.github.com> Date: Wed, 27 Dec 2023 05:02:36 -0800 Subject: [PATCH 10/14] Update README.md Co-authored-by: Jimmy Campbell --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5a2ea9e4..10a3c8f9 100644 --- a/README.md +++ b/README.md @@ -827,7 +827,8 @@ The `Allocation` setting of a feature flag has the following properties: | `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. | -In the above example, if the feature is not enabled, the feature manager will assign the variant allocated by `DefaultWhenDisabled` to the current user, which is `Small` in this case. +In the above example, if the feature is not enabled, the feature manager will assign the variant marked as `DefaultWhenDisabled` to the current user, which is `Small` in this case. + If the feature is enabled, the feature manager will check the `User`, `Group`, and `Percentile` allocations in that order to assign a variant. If the user being evaluated is named `Marsha`, in the group named `Ring1`, or the user happens to fall between the 0 and 10th percentile calculated with the given `Seed`, then the specified variant is assigned to the user. In this case, all of these would return the `Big` variant. If none of these allocations match, the user is assigned the `DefaultWhenEnabled` variant, which is `Small`. From 90aedf342a58e8b326c93bc4b46aae7a3e1c9ccf Mon Sep 17 00:00:00 2001 From: AMER JUSUPOVIC Date: Wed, 27 Dec 2023 05:03:41 -0800 Subject: [PATCH 11/14] update section titles --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5a2ea9e4..57c19f41 100644 --- a/README.md +++ b/README.md @@ -737,7 +737,7 @@ IConfigurationSection variantConfiguration = variant.Configuration; // Do something with the resulting variant and its configuration ``` -### Defining a Feature's Variants +### Defining Variants Each variant has two properties: a name and a configuration. The name is used to refer to a specific variant, and the configuration is the value of that variant. The configuration can be set using either the `ConfigurationReference` or `ConfigurationValue` properties. `ConfigurationReference` is a string path that references a section of the current configuration that contains the feature flag declaration. `ConfigurationValue` is an inline configuration that can be a string, number, boolean, or configuration object. If both are specified, `ConfigurationValue` is used. If neither are specified, the returned variant's `Configuration` property will be null. @@ -771,7 +771,7 @@ A list of all possible variants is defined for each feature under the `Variants` } ``` -### Allocating a Feature's Variants +### Allocating Variants The process of allocating a feature's variants is determined by the `Allocation` property of the feature. From 15ad38d8971f93da152db12a83c7a789a1b78e9a Mon Sep 17 00:00:00 2001 From: AMER JUSUPOVIC Date: Wed, 27 Dec 2023 05:58:40 -0800 Subject: [PATCH 12/14] resolve comments --- README.md | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 0946c8ac..3553a986 100644 --- a/README.md +++ b/README.md @@ -722,21 +722,31 @@ public class Variant ### Getting Variants -For each feature, a variant can be retrieved using the `IVariantFeatureManager`'s `GetVariantAsync` method. The variant returned is dependent on the -user currently being evaluated, and that information is obtained from an instance of `TargetingContext`. This context can either be passed in when -calling `GetVariantAsync` or it can be automatically retrieved from an implementation of `ITargetingContextAccessor` if one is registered. +For each feature, a variant can be retrieved using the `IVariantFeatureManager`'s `GetVariantAsync` method. ``` C# … IVariantFeatureManager featureManager; … -Variant variant = await featureManager.GetVariantAsync(MyFeatureFlags.FeatureU); +Variant variant = await featureManager.GetVariantAsync(MyFeatureFlags.FeatureU, CancellationToken.None); IConfigurationSection variantConfiguration = variant.Configuration; // Do something with the resulting variant and its configuration ``` +Once a variant is retrieved, the configuration of a variant can be used directly as an `IConfigurationSection` from the variant's `Configuration` property. Another option is to bind the configuration to an object using .NET's configuration binding pattern. + +``` C# +IConfigurationSection variantConfiguration = variant.Configuration; + +MyFeatureSettings settings = new MyFeatureSettings(); + +variant.Configuration.Bind(settings); +``` + +The variant returned is dependent on the user currently being evaluated, and that information is obtained from an instance of `TargetingContext`. This context can either be passed in when calling `GetVariantAsync` or it can be automatically retrieved from an implementation of [`ITargetingContextAccessor`](#itargetingcontextaccessor) if one is registered. + ### Defining Variants Each variant has two properties: a name and a configuration. The name is used to refer to a specific variant, and the configuration is the value of that variant. The configuration can be set using either the `ConfigurationReference` or `ConfigurationValue` properties. `ConfigurationReference` is a string path that references a section of the current configuration that contains the feature flag declaration. `ConfigurationValue` is an inline configuration that can be a string, number, boolean, or configuration object. If both are specified, `ConfigurationValue` is used. If neither are specified, the returned variant's `Configuration` property will be null. @@ -829,8 +839,7 @@ The `Allocation` setting of a feature flag has the following properties: In the above example, if the feature is not enabled, the feature manager will assign the variant marked as `DefaultWhenDisabled` to the current user, which is `Small` in this case. - -If the feature is enabled, the feature manager will check the `User`, `Group`, and `Percentile` allocations in that order to assign a variant. If the user being evaluated is named `Marsha`, in the group named `Ring1`, or the user happens to fall between the 0 and 10th percentile calculated with the given `Seed`, then the specified variant is assigned to the user. In this case, all of these would return the `Big` variant. If none of these allocations match, the user is assigned the `DefaultWhenEnabled` variant, which is `Small`. +If the feature is enabled, the feature manager will check the `User`, `Group`, and `Percentile` allocations in that order to assign a variant. For this particular example, if the user being evaluated is named `Marsha`, in the group named `Ring1`, or the user happens to fall between the 0 and 10th percentile, then the specified variant is assigned to the user. In this case, all of these would return the `Big` variant. If none of these allocations match, the user is assigned the `DefaultWhenEnabled` variant, which is `Small`. 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. From 6097fc5846bcdf703b9ce2e6f14504fec808006a Mon Sep 17 00:00:00 2001 From: AMER JUSUPOVIC Date: Wed, 27 Dec 2023 05:59:55 -0800 Subject: [PATCH 13/14] fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3553a986..d636f3ce 100644 --- a/README.md +++ b/README.md @@ -742,7 +742,7 @@ IConfigurationSection variantConfiguration = variant.Configuration; MyFeatureSettings settings = new MyFeatureSettings(); -variant.Configuration.Bind(settings); +variantConfiguration.Bind(settings); ``` The variant returned is dependent on the user currently being evaluated, and that information is obtained from an instance of `TargetingContext`. This context can either be passed in when calling `GetVariantAsync` or it can be automatically retrieved from an implementation of [`ITargetingContextAccessor`](#itargetingcontextaccessor) if one is registered. From 95c2f4f9feb626d5de486745b53fff8bcaf3ba18 Mon Sep 17 00:00:00 2001 From: AMER JUSUPOVIC Date: Fri, 5 Jan 2024 09:57:05 -0800 Subject: [PATCH 14/14] update link to allocating variants section --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d636f3ce..bfc22005 100644 --- a/README.md +++ b/README.md @@ -703,7 +703,7 @@ In the above example, the feature will be enabled for users named `Jeff` and `Al When new features are added to an application, there may come a time when a feature has multiple different proposed design options. A common solution for deciding on a design is some form of A/B testing, which involves providing a different version of the feature to different segments of the user base and choosing a version based on user interaction. In this library, this functionality is enabled by representing different configurations of a feature with variants. -Variants enable a feature flag to become more than a simple on/off flag. A variant represents a value of a feature flag that can be a string, a number, a boolean, or even a configuration object. A feature flag that declares variants should define under what circumstances each variant should be used, which is covered in greater detail in the [Allocating a Feature's Variants](./README.md#allocating-a-features-variants) section. +Variants enable a feature flag to become more than a simple on/off flag. A variant represents a value of a feature flag that can be a string, a number, a boolean, or even a configuration object. A feature flag that declares variants should define under what circumstances each variant should be used, which is covered in greater detail in the [Allocating Variants](./README.md#allocating-variants) section. ``` C# public class Variant