1.0.0 • Published 2 years ago

feature-with-flags v1.0.0

Weekly downloads
-
License
ISC
Repository
github
Last release
2 years ago

feature-with-flags

feature-with-flags is a typescript library to implement feature flags for javascript applications. Name inspired from Sheldon Coopers fun with flags program.

What are feature flags?

Feature flags (also commonly known as feature toggles) are a software engineering technique that turns select functionality on and off during runtime, without deploying new code.

Installation

Install the package using npm or yarn by

npm install --save feature-with-flags

or

yarn add feature-with-flags

Usage

# ES6

import FeatureFlag from "feature-with-flags";

# CommonJs

const FeatureFlag = require('feature-with-flags');

Initialise FeatureFlag and pass feature flag configuration to it

const featureFlags = new FeatureFlag(FEATURE_FLAGS_CONFIGURATION);

const { isActive } = featureFlags();

You can get the status of a feature flag by passing some of its details to the isActive method

const { status, message } = isActive(FEATURE_FLAG_DETAILS);

status is a boolean which tells if a feature flag is enabled or not

message is a null | string, a message if there's wrong with the passed in feature flag details

# enable a feature by

// If status is true, apply the new logic if not use the same existing logic

if(status) {
  useNewLogic();
} else {
  useExistingLogic();
}

Internals

In this section, we will discuss the internals of feature-with-flags library.

Feature Flag Configurations Object

feature-with-flags expects feature flag configurations object in the below shape

  • Sample configuration
  
 const featureFlagConfigurations = {
  featureFlag1: {
   enable: true
  },
  featureFlag2: {
   enable: false
  }
 }
  • Complex configuration
  
 const featureFlagConfigurations = {
  featureFlag1: {
   enable: true,
   activationStrategies: ['UserRoleActivationStrategy', 'ReleaseDateActivationStrategy'],
   roles: ['ROLE_1', 'ROLE_2']
  },
  featureFlag2: {
    enable: false,
    activationStrategies: "UserWithIDActivationStrategy",
    userIDs: ['USER_ID_1', 'abc', 'xyz'],
  },
   .... other feature flags
 }

Examples of feature flags which are very granual

  • Show the feature only for users who has ADMIN role
  • Enable the feature for just US region
  • This feature will be shown only at specific date
  • and many more.....

You see the list goes on.

Activation Stratigies

UserRoleActivationStrategy

ActivationStrategy implementation based on roles of the current user. As far as the user has at least one of configured roles then the feature will be active.

Usage

Configuration:
# sample example

featureFlagConfigurations: {
  alpha: { // Name of the feature flag
    enable: true,
    activationStrategies: ["UserRoleActivationStrategy"],

    userRoles:["admin", "phoenix"], //This key is must a provided for as UserRoleActivationStrategy looks for userRoles in the config,
    .... other configurations
  },
}
   
Context:

When the featureFlag contains UserRoleActivationStrategy then the end user needs to pass the key userRole while checking the status.

 const featureFlagConfig = new FeatureFlag("YOUR_FEATURE_FLAG_CONFIGURATION");
 
 const { isActive } = featureFlagConfig;
 
 const featureFlagContext = {
 
  // This is a must provided key
  userRole: 'LOGGED_IN_USER_ROLE' //feature-with-flags will take this key and lookover the userRoles provided in the configuration.
  
 }
 const { status, message } = isActive("alpha", featureFlagContext);
 

UserWithIDActivationStrategy

ActivationStrategy implementation based on the ID of the current user. As far as the user has at least one of configured IDs then the feature will be active.

Usage

Configuration:
# sample example

featureFlagConfigurations: {
  alpha: { // Name of the feature flag
    enable: true,
    activationStrategies: ["UserWithIDActivationStrategy"],

    userIDs:["ID1", "ID2"], //This key is must a provided for as UserWithIDActivationStrategy looks for userIDs in the config,

    .... other configurations
  },
}
   
Context:

When the featureFlag contains UserWithIDActivationStrategy then the end user needs to pass the key userID while checking the status.

 const featureFlagConfig = new FeatureFlag("YOUR_FEATURE_FLAG_CONFIGURATION");

 const { isActive } = featureFlagConfig;

 const featureFlagContext = {

    // This is a must provided key
   // feature-with-flags will take this key and lookover the userIDs provided in the configuration.

    userID: 'LOGGED_IN_USER_ID' 

 }
 const { status, message } = isActive("alpha", featureFlagContext);

RegionActivationStrategy

ActivationStrategy implementation based on the region of the current user. As far as the user has at least one of configured regions then the feature will be active.

Usage

Configuration:
# sample example

featureFlagConfigurations: {
  alpha: { // Name of the feature flag
    enable: true,
    activationStrategies: ["RegionActivationStrategy"],

    regions:["region1", "region2"], //This key is must a provided for as RegionActivationStrategy looks for regions in the config,

    .... other configurations
  },
}
   
Context:

When the featureFlag contains RegionActivationStrategy then the end user needs to pass the key region while checking the status.

 const featureFlagConfig = new FeatureFlag("YOUR_FEATURE_FLAG_CONFIGURATION");

 const { isActive } = featureFlagConfig;

 const featureFlagContext = {
     // This is a must provided key
    //feature-with-flags will take this key and lookover the regions provided in the configuration.

    region: 'USER_REGION'
 };

 const { status, message } = isActive("alpha", featureFlagContext);

DeviceTypeActivationStrategy

ActivationStrategy implementation based on the device type of the current user. As far as the user has at least one of configured device types then the feature will be active.

Usage

Configuration:
# sample example

featureFlagConfigurations: {
  alpha: { // Name of the feature flag
    enable: true,
    activationStrategies: ["DeviceTypeActivationStrategy"],

   // This key is must a provided for as DeviceTypeActivationStrategy looks for deviceTypes in the config,
    deviceTypes:["desktop", "mobile"], 

    .... other configurations
  },
}
   
Context:

When the featureFlag contains DeviceTypeActivationStrategy then the end user needs to pass the key deviceType while checking the status.

 const featureFlagConfig = new FeatureFlag("YOUR_FEATURE_FLAG_CONFIGURATION");

 const { isActive } = featureFlagConfig;

 const featureFlagContext = {

  // This is a must provided key
  deviceType: navigator.userAgent //feature-with-flags will take this key and lookover the deviceTypes provided in the configuration.
 };

 const { status, message } = isActive("alpha", featureFlagContext);

TenantActivationStrategy

ActivationStrategy implementation based on the tenant id of the current user. As far as the user has at least one of configured tenant ids then the feature will be active.

Usage

Configuration:
# sample example

featureFlagConfigurations: {
  alpha: { // Name of the feature flag
    enable: true,
    activationStrategies: ["TenantActivationStrategy"],

    // This key is must a provided for as TenantActivationStrategy looks for tenantIDs in the config,
    tenantIDs:["tenant1", "tenant2"],

    .... other configurations
  },
}
   
Context:

When the featureFlag contains TenantActivationStrategy then the end user needs to pass the key tenantID while checking the status.

 const featureFlagConfig = new FeatureFlag("YOUR_FEATURE_FLAG_CONFIGURATION");

 const { isActive } = featureFlagConfig;

 const featureFlagContext = {

    // This is a must provided key
   //feature-with-flags will take this key and lookover the tenantIDs provided in the configuration.
  tenantID: "TENANT_ID"
 };

 const { status, message } = isActive("alpha", featureFlagContext);

ClientIdActivationStrategy

ActivationStrategy implementation based on the client id of the current user. As far as the user has at least one of configured client ids then the feature will be active.

Usage

Configuration:
# sample example

featureFlagConfigurations: {
  alpha: { // Name of the feature flag
    enable: true,
    activationStrategies: ["ClientIdActivationStrategy"],

    // This key is must a provided for as ClientIdActivationStrategy looks for clientIDs in the config,
    clientIDs:["client1", "client2"],

    .... other configurations
  },
}
   
Context:

When the featureFlag contains ClientIdActivationStrategy then the end user needs to pass the key clientID while checking the status.

 const featureFlagConfig = new FeatureFlag("YOUR_FEATURE_FLAG_CONFIGURATION");

 const { isActive } = featureFlagConfig;

 const featureFlagContext = {

   // This is a must provided key
  //feature-with-flags will take this key and lookover the clientIDs provided in the configuration.
  clientID: "CLIENT_ID"

 };

 const { status, message } = isActive("alpha", featureFlagContext);

ReleaseDateActivationStrategy

ActivationStrategy implementation based on the release date. When the current date is beyond or equal to the user provided release date then the feature will be active.

Usage

Configuration:
# sample example

featureFlagConfigurations: {

  alpha: { // Name of the feature flag
    enable: true,
    activationStrategies: ["ReleaseDateActivationStrategy"],

    // releaseDate should be in "November 21, 2021" or "12/26/2021" // MM/DD/YYYY format. 
    releaseDate: "November 21, 2021", //This key is must a provided for as ReleaseDateActivationStrategy looks for releaseDate in the config,

    .... other configurations
  },
}
   
Context:
 const featureFlagConfig = new FeatureFlag("YOUR_FEATURE_FLAG_CONFIGURATION");

 const { isActive } = featureFlagConfig;

 const { status, message } = isActive("alpha");

DateTimeActivationStrategy

ActivationStrategy implementation based on the release date with time. When the current date is beyond or equal to the user provided release date then the feature will be active.

Usage

Configuration:
# sample example

featureFlagConfigurations: {
  alpha: { // Name of the feature flag
    enable: true,
    activationStrategies: ["DateTimeActivationStrategy"],

    // Format: DD/MM/YYY/HOURS:MINUTES:SECONDS
    releaseDateWithTime: "11/11/2021/16:50:10,
   // Note: releaseDateWithTime should be in this format. This key is must a provided for as DateTimeActivationStrategy looks for releaseDateWithTime in the config,

    .... other configurations
  },
}
   
Context:
 const featureFlagConfig = new FeatureFlag("YOUR_FEATURE_FLAG_CONFIGURATION");

 const { isActive } = featureFlagConfig;

 const { status, message } = isActive("alpha");

FlexibleRolloutActivationStrategy

ActivationStrategy implementation based on the unique id of the current user. As far as the user threshold value is within the range of user provided rolloutPercentage then the feature will be active.

How does this strategy work?

If you want to enable a feature for a fixed percentage of users randomly, you need to pass the percentage range (0 -100) and a unique identifier for each logged in user typically userID. Internally feature-with-flags calculates user threshold value (a unique number that is always the same based on feature flag name & unique user id) check with rolloutPercentage, if the user threshold value is less than rolloutPercentage then the feature will be active

Usage

Configuration:
# sample example

featureFlagConfigurations: {
  alpha: { // Name of the feature flag
    enable: true,
    activationStrategies: ["FlexibleRolloutActivationStrategy"],

    rolloutPercentage: 40, // This key is must a provided for as FlexibleRolloutActivationStrategy looks for rolloutPercentage in the config,

    .... other configurations
  },
}
   
Context:

When the featureFlag contains FlexibleRolloutActivationStrategy then the end user needs to pass a unique identifier userID while checking the status.

 const featureFlagConfig = new FeatureFlag("YOUR_FEATURE_FLAG_CONFIGURATION");

 const { isActive } = featureFlagConfig;

 const featureFlagContext = {

  // This is a must provided key
  userID: "ANY_UNIQUE_IDENTIFIER_ACROSS_USERS"

 }

 const { status, message } = isActive("alpha", featureFlagContext);

default

If the user didn't pass any activation strategy, feature-with-flags consider it as default activation strategy, the status of this feature flag will be depend on the enabled key.

- If using normal configuration
# sample example

featureFlagConfigurations: {
  alpha: { // Name of the feature flag
    enable: true
  },
}
   
Context:
 const featureFlagConfig = new FeatureFlag("YOUR_FEATURE_FLAG_CONFIGURATION");

 const { isActive } = featureFlagConfig;

 const { status, message } = isActive("alpha");

Generic error messages

In this section, you will find all the types of messages feature-with-flags will send to the user when there is an error. This will help the developer to debug why the feature flag is not working as expected.

## When the user passes a feature flag name that is not part of his/her feature flag configuration

message: feature flag name: FEATURE_FLAG_NAME is not found, please check your configuration.

## In the above Activation Strategies section you will find the required key in config & context for each strategy

// Case 1: If the user didn't pass or misspells the required CONFIG key for the activation strategy

Message: `Activation strategy: ${YOUR_STRATEGY_NAME} missing lookup ${REQUIRED_STRATEGY_CONFIG_KEY} in the config for feature flag: ${YOUR_FEATURE_FLAG_NAME}`

// Case 2: If the user didn't pass or misspells the required CONTEXT key for the activation strategy

Message: `Activation strategy: ${YOUR_STRATEGY_NAME} missing lookup ${REQUIRED_STRATEGY_CONTEXT_KEY} in the context for feature flag: ${YOUR_FEATURE_FLAG_NAME}`

// Case 3: If the user didn't pass or misspells the required CONFIG & CONTEXT key for the activation strategy

Message: `Activation strategy: ${YOUR_STRATEGY_NAME} requires ${REQUIRED_STRATEGY_CONFIG_KEY} in the config object and ${REQUIRED_STRATEGY_CONTEXT_KEY} in the context object as lookup for feature flag: ${YOUR_FEATURE_FLAG_NAME}`

// Case 4: When the user passes a feature flag name that is not present in the configuration

Message: `feature flag name: ${YOUR_FEATURE_FLAG_NAME} is not found, please check the configuration`

// Case 5: When the user passed context key value not matched with the value of configuration for an activation strategy

Message: `${CONTEXT_VALUE} is not found in ${CONFIG_KEYS}` 

Ex: userId: 123 is not found in userID's configuration

Contact

Contact @Manoj Kumar Gangavarapu (manoj.gangavarapuu@gmail.com) in case of any queries.

Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.

Please make sure to update tests as appropriate.

License

MIT