Use cases
Remote configuration
Remote configuration refers to the ability of modifying the behaviour or settings of an application while it is running, without the need for restarting, redeploying, or making any code changes.
This approach allows developers and system administrators to adjust various aspects of an application's behaviour, such as feature availability or other configuration parameters, without requiring downtime or disrupting the application's ongoing operation.
Benefits#
Separating runtime configuration from your application using Featurevisor brings in a lot of benefits:
- Flexibility & agility: Allows for greater flexibility in adapting the application's behavior to changing business requirements, user preferences, or market conditions.
- Reduced time & effort: Configuration changes can be made independently without the need for application deployments, reducing time and effort.
- Personalized experience: Allows for targeted configuration of features or settings to specific users or groups of users, such as beta testers, internal users, or paying customers.
- Reduced risk & downtime: It eliminates the need for deploying new application code or taking the application offline, reducing the potential for introducing bugs or causing downtime during configuration updates.
- Auditing & versioning: Facilitates tracking and auditing changes made to configuration settings. It enables versioning of configuration parameters, ensuring that previous configurations can be reverted if needed and providing a clear history of configuration changes for troubleshooting or compliance purposes.
- Multi-environment: Allows for different configurations to be applied in different environments, such as development, testing, staging, and production.
Our application#
Let's assume we have an e-commerce web application, where we wish to parameterize several aspects of it as configuration.
The application allows its users to:
- browse products
- sign up and in
- add products to cart
- pay for the products (checkout)
- manage their account
Configuration parameters#
We can identify the following configuration parameters that we wish to manage during the checkout flow:
- list of payment methods (like credit card, PayPal, etc.)
- list of credit cards (like Visa, Mastercard, AMEX, etc.)
- list of shipping methods (like standard, express, etc.)
- allow discount code (or gift card)
Understanding the building blocks
Before going further in this guide, you are recommended to learn about the building blocks of Featurevisor to understand the concepts used in this guide:
- Attributes: building block for conditions
- Segments: conditions for targeting users
- Features: feature flags and variables with rollout rules
- SDKs: how to consume datafiles in your applications
The quick start can be very handy as a summary.
Defining our feature#
We can start by creating a new feature called checkout
:
description: Checkout flow configurationtags: - checkoutbucketBy: userId# rolled out as `true` to 100% of our trafficrules: production: - key: everyone segments: '*' # everyone percentage: 100
Variables#
Featurevisor supports variables that can be used to define configuration parameters.
We can extend our feature to include variable schema starting with paymentMethods
:
description: Checkout flow configurationtags: - checkoutbucketBy: userId# we add variable schema for all our parameters here,# starting with `paymentMethods` for nowvariablesSchema: paymentMethods: type: array defaultValue: - creditCard - paypal - applePay - googlePayrules: production: - key: everyone segments: '*' # everyone percentage: 100
By default, we are saying that all our users will be able to use all the payment methods.
Evaluating variables using SDK#
Once we have built and deployed our datafiles, we can start consuming them in our application using Featurevisor SDKs.
We initialize the SDK first:
import { createInstance } from '@featurevisor/sdk'const DATAFILE_URL = 'https://cdn.yoursite.com/datafile.json'const datafileContent = await fetch(DATAFILE_URL) .then((res) => res.json())const f = createInstance({ datafile: datafileContent,})
Now we can evaluate the variable in our application:
const featureKey = 'checkout'const variableKey = 'paymentMethods'const context = { userId: 'user-123', country: 'nl' }const paymentMethods = f.getVariable(featureKey, variableKey, context)console.log(paymentMethods)// [// "creditCard",// "paypal",// "applePay",// "googlePay"// ]
With this evaluated ordered array of payment methods in the runtime, we can now render the list of payment methods in our checkout flow of the application without having to hardcode this list anywhere.
Overriding variables by rules#
From above example, we can see that all our users will be able to use all the payment methods.
But what if we want to restrict some payment methods to some users based in certain countries?
We can do that by overriding the variables via our rollout rules.
Assuming we already have a segment created for targeting users in the Netherlands:
description: Target users in the Netherlandsconditions: - attribute: country operator: equals value: nl
We can now use this segment in our rollout rules and override the paymentMethods
variable:
# ...rules: production: - key: nl segments: netherlands percentage: 100 variables: paymentMethods: - paypal - ideal - key: everyone segments: '*' percentage: 100
Now when we evaluate our features, we will get different results for users in the Netherlands:
// Users in the Netherlandsconst context = { userId: 'user-234', country: 'nl' }const paymentMethods = f.getVariable(featureKey, variableKey, context)console.log(paymentMethods)// [// "paypal",// "ideal"// ]
While rest of the world will still get the same result as before (that is the default value as defined in the variable schema):
// Users in the USconst context = { userId: 'user-123', country: 'us' }const paymentMethods = f.getVariable(featureKey, variableKey, context)console.log(paymentMethods)// [// "creditCard",// "paypal",// "applePay",// "googlePay"// ]
Other ways of overriding variables#
Depending on your needs, it is also possible to override variables:
- at each variation level acting as an experiment, and also
- at environment level by forcing it
You can see other use cases here detailing these approaches:
How do applications get latest configuration?#
There are two ways this can happen:
- You can configure your SDK to keep refreshing the datafile at a certain interval (like every 30 seconds), or
- When deploying your Featurevisor datafiles, you can broadcast a notification to all your applications to refresh their datafiles manually enabling over the air updates
You can refer to the SDK guide here for refreshing datafile.
Full feature example#
Based on our original requirements, we can express the checkout
feature with all its variables as follows:
description: Checkout flow configurationtags: - checkoutbucketBy: userIdvariablesSchema: paymentMethods: type: array defaultValue: - creditCard - paypal - applePay - googlePay creditCards: type: array defaultValue: - visa - mastercard - amex shippingMethods: type: array defaultValue: - standard - express allowDiscountCode: type: boolean defaultValue: falserules: production: - key: nl segments: netherlands percentage: 100 variables: paymentMethods: - paypal - ideal allowDiscountCode: true - key: everyone segments: '*' percentage: 100
Based on our requirements, we can keep overriding these variables against different rules as needed.
Learn more about variables, its supported types, and how to override them in features documentation.
Conclusion#
We learned about:
- various benefits of separating runtime configuration from our application
- how to break down different configuration parameters of our application into variables
- having them defined in a feature declaratively using Featurevisor
- overriding them using rollout rules based on our needs
Overall, Featurevisor can help manage your application's runtime configuration in a highly readable and maintainable way for your team and your organization, with a strong review and approval process in one single place for everyone in the form of a Git repository.