Feature management
DEM Feature management provides a centralized but extensible way for adding feature flags (https://martinfowler.com/articles/feature-toggles.html) to your mobile application. This lets you roll out new features to a subset of users, limiting the availability of a feature by time, or performing A/B tests, for example. The Feature Management classes also manage feature flag lifecycles behind the scenes. For example, the libraries refresh and cache flag states, or guarantee a flag state to be immutable during a request call.
Set up feature management
The DEM feature manager IFeatureManager
gets feature flags from the framework's native configuration system. You can register the feature management services by using standard conventions in application:
protected override void RegisterTypes(ITypeCatalog typeCatalog)
{
typeCatalog.AddOrUpdate(
new AppServiceInfo<FeatureManager, IFeatureManager>() { IsSingleInstance = true }
);
By default, the feature manager retrieves feature flags from the FactoryConfig_FeatureSettings
section of the DEM configuration data.
Feature flag declaration
Each feature flag has two parts: a name and a list of one or more filters that are used to evaluate if a feature's state is on (that is, when its value is True). A filter defines a use case for when a feature should be turned on. The following example shows how to set up feature flags in a JSON file:
{
"FeatureSettings": [
{
"Name": "StandingOrders",
"IsEnabled": true
},
{
"Name": "GetCardImagesFromServer",
"IsEnabled": false
}
]
}
By convention, the FeatureSettings section of this JSON document is used for feature flag settings. The prior example shows three feature flags with their filters defined in the IsEnabled property:
- Feature StandingOrders is on.
- Feature GetCardImagesFromServer is off.
Feature flag references
So that you can easily reference feature flags in code, you should define them as enum variables:
public enum Features
{
StandingOrders,
HasTransfersSelection,
Biometric,
GetCardImagesFromServer,
PublicBeneficiaries
}
Feature flag checks
The basic pattern of feature management is to first check if a feature flag is set to on. If so, the feature manager then runs the actions that the feature contains. For example:
if (App.IsFeatureEnabled(nameof(Features.StandingOrders)))
{
…
}
Dependency injection
In DEM, you can access the feature manager IFeatureManager through dependency injection:
public class HomeViewModel : PageViewModel
{
protected readonly IFeatureManager _featureManager;
public HomeViewModel(IFeatureManager featureManager)
{
_featureManager = featureManager;
}
}
if (featureManager?.IsEnabled(nameof(Features.GetCardImagesFromServer)) ?? false)
Feature management usecaes
Screen is available only in debug mode from settings menu
Current experimental flags
Using functionality that's behind an experimental flag requires you to enable the flag, or flags, in your application
Just add FactoryConfig_FeatureSettings
to your environment configuration in Solution with JSON.
{
"FeatureSettings": [
{
"Name": "StandingOrders",
"IsEnabled": true
},
{
"Name": "IPS",
"IsEnabled": true
},
{
"Name": "Cards",
"IsEnabled": true
},
{
"Name": "GetCardImagesFromServer",
"IsEnabled": true
},
{
"Name": "HasTransfersSelection",
"IsEnabled": false
},
{
"Name": "Biometric",
"IsEnabled": false
},
{
"Name": "Corporate",
"IsEnabled": false
},
{
"Name": "OnBording",
"IsEnabled": true
},
{
"Name": "IsUsingLatestVersion",
"IsEnabled": false
},
{
"Name": "TabbedPages",
"IsEnabled": false
},
{
"Name": "PushMessages",
"IsEnabled": false
},
{
"Name": "ViewModelTracker",
"IsEnabled": false
},
{
"Name": "Maps",
"IsEnabled": true
},
{
"Name": "GetLogoFromServer",
"IsEnabled": false
},
{
"Name": "ScheduleMeeting",
"IsEnabled": true
},
{
"Name": "ForeignCurrencyIncomes",
"IsEnabled": false
},
{
"Name": "Applications",
"IsEnabled": false
},
{
"Name": "MyDocuments",
"IsEnabled": false
},
{
"Name": "PreloginBalances",
"IsEnabled": false
},
{
"Name": "PushnotificationList",
"IsEnabled": false
},
{
"Name": "Cheques",
"IsEnabled": false
},
{
"Name": "PaymentAPIAuthorization",
"IsEnabled": false
},
{
"Name": "ClinetComplaint",
"IsEnabled": false
},
{
"Name": "CrossBorderPaymentStatistics",
"IsEnabled": false
},
{
"Name": "PaymentWithScannedQR",
"IsEnabled": false
},
{
"Name": "RequestToPayGenerate",
"IsEnabled": false
},
{
"Name": "AuthorizationPendingOnExchange",
"IsEnabled": false
},
{
"Name": "TermDepositNegotiation",
"IsEnabled": false
},
{
"Name": "Calendar",
"IsEnabled": false
},
{
"Name": "CASSettings",
"IsEnabled": false
},
{
"Name": "PublicBeneficiaries",
"IsEnabled": false
},
]
}