Mikhail Potter

Feature flags in GitLab

Feature flag is a concept that allows to enable and disable features without the need to redeploy application. They provide much flexible way to manage features’ lifecycle. With feature flags you would have the following advantages:

However, along with advantages you usually get a set of trade offs:

There are a number of solutions for feature flags management like FlagSmithGrowthBookFliptUnleash and others. However, if you already use GitLab, you can use its feature flags feature. Since version 13.5 GitLab is integrated with Unleash and provides both UI and API for feature flags management.

In the Feature Flags section of GitLab UI you can create feature flags and enable them either for all or specific environments and users.

To integrate an application with the API it is necessary to click Configure and copy API URL and Instance ID. The following example code would be in Java, but any backend can be integrated with it. Unleash has SDKs for all popular stacks.

The first step is to add SDK dependency to the project:

<dependency>  
  <groupId>io.getunleash</groupId>  
  <artifactId>unleash-client-java</artifactId>  
  <version>Latest version here</version>  
</dependency>

Then it is necessary to put API URL and Instance ID to properties. Here unleash.env set additionally. It allows application to be aware on which environment it was launched. So we can turn a feature on or off for it.

unleash:   
  url: https://gitlab.noveogroup.com/api/v4/feature_flags/unleash/4321   
  key: SDFasfsfasfdFDsafD   
  env: localya

Then we define Unleash bean with the parameters above. Using UnleashConfig it is possible to configure other useful parameters, e.g. default value in case feature flag does not exist, or delay for a client to fetch actual flags’ state.

@Configuration   
public class UnleashConfiguration {   
   
 @Bean   
 public Unleash unleash(   
   @Value("${unleash.url}") final String url,   
   @Value("${unleash.key}") final String instanceId,   
   @Value("${unleash.env}") final String env   
 ) {   
   return new DefaultUnleash(   
     UnleashConfig.builder()   
                  .unleashAPI(url)   
                  .instanceId(instanceId)   
                  .appName(env)   
                  .build()   
   );   
 }   
   
}

Now lets define some feature flag. Actually, feature flag is defined by its name. However, for the sake of type safety let store it as enum.

@Getter   
public enum FeatureToggleType {   
   
  AWESOME_FEATURE("awesome-feature");   
   
  private final String code;   
   
  FeatureToggleType(final String code) {   
    this.code = code;   
  }   
   
}

To fetch feature flag info from API we need appropriate class to put values into:

@Getter   
@Setter   
@NoArgsConstructor   
@AllArgsConstructor   
public class FeatureToggle {   
  private String name;  
  private boolean enabled;  
}

And define a service that can check feature flag state or fetch a list of flags available for the current environment. Our application proxies requests to Unleash for frontend not to have additional dependencies. So, the latter method helps to provide necessary data.

@Service   
public class FeatureToggleService {   
   
  private final Unleash unleash;   
   
  public FeatureToggleServiceImpl(final Unleash unleash) {   
    this.unleash = unleash;   
  }   
   
  public boolean isEnabled(final FeatureToggleType featureToggle) {   
    return unleash.isEnabled(featureToggle.getCode());   
  }   
   
  public List<FeatureToggle> list() {   
    return unleash.more().evaluateAllToggles().stream()   
                  .map(toggle -> new FeatureToggle(toggle.getName(), toggle.isEnabled()))   
                  .collect(Collectors.toList());   
  }   
   
}

And the last step is to add condition to check feature flag and launch necessary logic:

if (featureToggleServive.isEnabled(FeatureToggleType.AWESOME_FEATURE)) {  
  awesomeStrategy.execute();  
} else {  
  legacyStrategy.execute();  
}

GitLab feature flags work great for relatively small projects as it has its limitations. For bigger project you can use Unleash directly. Fortunately, migration shouldn’t be that hard.

#GitLab #CI #Feature Flags