Feature Gating part 3 : how can we check the gates?
Feature Gating part 3 : how can we check the gates?

Feature Gating part 3 : how can we check the gates?

2018, Mar 07    

In this article we’ll explore few ways to check if the feature gates are opened or not. This is the third episode of our series about Feature Gating, last time we discussed about the optimal persistence method for the flags.

The first approach is a static config object injected as dependency in the class cTor:

interface IFoo{
   bar():void;
}

interface FlagsConfig{
  featureX:boolean;
}

export class Foo implements IFoo{
   constructor(private readonly flagsConfig:FlagsConfig){}

   public bar(){
       if(this.flagsConfig.featureX){
           /*.......*/
       }else{
           /*.......*/
       }
   }
};

It’s simple, easy to implement and does the job. The configuration object can be instantiated in the composition root reading data from whatever is your persistence layer  and you’re done.

Drawbacks? It’ static. That means you cannot vary your flags based on custom conditions (eg. logged user, time, geolocation).

So what can we do? Something like this:

interface IFeatureService{
   isEnabled(featureName:string):boolean;
}

export class Foo implements IFoo{
   constructor(private readonly featureService:IFeatureService){}

   public bar(){
       if(this.featureService.isEnabled("feature-x")){
           /*.......*/
       }else{
           /*.......*/
       }
   }
};

Replacing the configuration object with a specific service will do the job. This is probably the most common situation and personally I’m quite a fan. The only drawback is the infamous tech debt: very soon the code will be filled with if/else statements. Should we leave them? Remove them? If yes, when? We will discuss in another article a simple strategy for that.

Speaking about strategy, it’s a very interesting pattern that we can exploit:

export class Foo implements IFoo{
   constructor(private readonly barStrategy:()=>void){}
   public bar(){
       this.barStrategy();
   }
};

// composition root
const featureService:IFeatureService = new FeatureService(),
   strategy1 = ():void =>{ /*...strategy 1...*/ },
   strategy2 = ():void =>{ /*...strategy 2...*/ },
   barStrategy:()=>void = featureService.isEnabled("feature-x") ? strategy1 : strategy2,
   foo:IFoo = new Foo(barStrategy);

The idea is to encapsulate the new and the old logic in two classes (lines 10 and 11) and generate a third one which will use featureService to pick the right instance.

Finally all you have to do is to inject that class in the consumer and you’re done.  

Next time: this is nice, but is really useful? What do we really get using Feature Gating?

Did you like this post? Then