Table of Contents
In this article, we will briefly introduce the feature flag pattern in java to allow uploading features to production that are not yet finalized.
It is very common to see projects that use the Feature Branch mechanism in order to have all the development of an isolated feature and once it is finalized, it can be integrated into the release flow and be able to generate a version.
Without going into a debate about the advantages and disadvantages of Feature Branch and Master Only, the Feature Branch strategy has a very expensive handicap, the feedback, if the feature takes, for example, a month to be finalized, that time will be at a minimum without being able to merge with the rest of the code, without being able to be tested with the rest of the functionalities, etc.
Yes, it is clear, with Feature Branch we can also have “fast” feedback, but for this we would need to adjust our pipeline so that it was aware of any branch that was created and could run a completely new environment per branch, with the cost that this implies, not only at the level of money, but to prepare environments, data etc., and even then, we would not be testing the integration of that feature with the rest.
Imagine that we can integrate our code and be able to put it in the release cycle of our application even without having the finished feature, one of the most obvious advantages is the quick feedback both in integrating our code with the rest of the application, as in minimizing the feared future merge conflicts.
Feature flag pattern to the rescue!
Feature Flag, also called Feature Toogle, is the perfect pattern to apply continuous integration to our long-running features.
Through a condition in our code and a configuration file we could activate or not functionality of our application in runtime and once the feature is finished we could activate it.
The simplest implementation would be a table in our database with the name of feature and status (Active or not) and in our code have an if (active) show else notshow.
But this pattern goes much further, allowing to activate a feature for a group of users, country, user’s browser, behavior or randomly.
Each of these implementations have different names, AbTesting, Canary Release .. but everything is about the same, exposing the feature or not depending on conditions.
Feature Flag pattern For Java
If our technological stack is made up of java or any language of the jvm we are lucky.
FF4J is the implementation of the Feature Toggle pattern in all its glory. With hardly any effort we have integration with different types of data sources to be able to save our features with their status, it also gives us audit of how many times the features have been applied, both by total number, by user, by origin.
It also has different decision strategies, WhiteList, BlackList, ClientFilter, ServerFilter, Weighting, etc … they also allow us to create our own strategy.
And all this is configurable through a web console or through API, which greatly facilitates the creation and maintenance of the Features.
Show me the code!
Although in the repository of the project there are many examples connecting with different sources for the features (jdbc, cassandra, mongo etc) I found it interesting to create an example that does not exist.
Let’s suppose we have a service for the configuration of all the features and other services are connected to this by http to consult the active features. In this example, I created a multimodule with two services:
Ffconsole
This service only has the administration console to create the features and a plugin to expose it through rest. To simplify the example, it is configured that way that the storage would be in memory and without any security (do not apply in productive environments ?).
The only configuration that we have is in the class FF4jServletConfiguration.kt in which we register the bean of FF4J, the servlet and the web console and we note the class so that it imports the beans necessary to expose the api. Also to simplify the example, I have the feature already registered, this should be done through the administration panel.
@Bean
fun getFF4j(): FF4j = FF4j().apply {
createFeature("AwesomeFeature", true)
}
@Bean
fun getFF4JServlet(): FF4jDispatcherServlet =
FF4jDispatcherServlet().apply { ff4j = getFF4j() }
@Bean
fun ff4jDispatcherServletRegistrationBean(): ServletRegistrationBean =
ServletRegistrationBean(getFF4JServlet(), "/ff4j-web-console/*")
My-awesome-web
A spring boot application with a controller that applies one logic or another depending on whether the feature is active or not. This application will connect to ffconsole using http. The configuration is as simple as telling you what the storage is:
@Bean
fun ff4j(): FF4j =
FF4j().apply {
featureStore = FeatureStoreHttp("http://ff4j-console:8080/api/ff4j")
}
and in the controller we have an endpoint which will return an HTTP_200 in case the feature is active and an HTTP_404 in case it is not.
@GetMapping("/")
fun home(): ResponseEntity =
ff.operateWith("AwesomeFeature",
ResponseEntity("Not available", HttpStatus.NOT_FOUND),
ResponseEntity("This is the awesome Feature", HttpStatus.OK))
This is the only code that once the feature is already implemented and tested enough in the productive environment, it should be cleaned and applied always without depending on whether the flag is active or not.
Here is my only snag of this library, the api to work with the features sin some functionality, in the case that there is no release a runtimeException for example, or dealing with the features is something imperative, so I have taken the freedom and chose this example to make a small wrapper and make it a little more “functional”, with which I expose three methods to work with the features:
fun enabled(featureID: String): Boolean =
getFeature(featureID)
.map { it.isEnable }
.orElse(false)
fun getFeature(featureID: String): Optional =
try {
Optional.of(ff4j.getFeature(featureID))
} catch (nf: FeatureNotFoundException) {
Optional.empty()
}
fun operateWith(featureId: String, nonExistsValue: T, existsValue: T): T =
getFeature(featureId)
.filter{it.isEnable}
.map { existsValue }
.orElse(nonExistsValue)
The project is assembled with a docker compose which with a make all generates the artifacts and raises two dockers to be able to make tests.
To access the administration part, we will do it by port 9090 under the context / ff4j-web-console / and for the part of the feature, it will be available on port 8080.
The whole project is in github.
Conclusion: Feature Flag pattern in java
This pattern should not be used as a hammer for all cases.
The best strategy is always to be able to split the functionalities / user stories into smaller ones to be able to integrate them as soon as possible, but there are always cases that the feature can not be delivered until it is 100% finalized and it is there where it applies.
The phase of cleaning the code once the feature is deployed and tested during the agreed time is very important, for the correct evolution and maintenance of the application.
Bibliography: Feature Flag pattern in java
If you would like to get more information about Feature Flag pattern in java, I highly recommend you to subscribe to our monthly newsletter by clicking here.
And if you found this article about Feature Flag pattern in Java useful, you might like…
Be more functional in Java with Vavr
Scala generics I: Scala type bounds
Scala generics II: covariance and contravariance
Scala generics III: Generalized type constraints
F-bound over a generic type in Scala
Microservices vs Monolithic architecture
iOS Objective-C app: sucessful case study
Mobile app development trends of the year
Banco Falabella wearable case study
Viper architecture advantages for iOS apps
Author
-
Software developer with over 15 years of experience, the last 9 years focussed on JVM. He can play different roles like Software developer, Software Architect, or Tech Lead, always following the best practices and leading by example, delivering high-quality code. Passionate about software craftsmanship and DevOps culture.
View all posts