Search results
Adding Feature Toggles to Spring Boot applications using Togglz
1. OVERVIEW
Features toggles help developers to make smaller, faster and less risky changes to software. Let’s say a requirement that will take a significant amount of effort to complete is going to be implemented. Two popular approaches are:
-
Branch the source code and develop for the next quarter or so. Once the implementation is completed you might likely face problems merging back this long-lived branch. You might end up asking your peers to stop committing changes or the SCM might get locked for the next 2-3 weeks until all the conflicts are resolved. Possibly delaying bug fixes and new features from being released to clients.
-
Implement the requirement in trunk / main / master branch, hiding incomplete functionality behind a development or release toogle. This allows the development team to work in the same code base, avoids the complexity of maintaining multiple branches, reduces the release cycle while getting a timely feedback when paired with a CI / CD pipeline.
This tutorial guides you to add feature flags in Spring Boot applications using Togglz and togglz-spring-boot-starter Spring Boot starter. How to configure and use them, some tradeoffs, and a word of caution.
2. REQUIREMENTS
- Java 7+.
- Maven 3.2+.
- Familiarity with Spring Framework.
3. APPLICATION DEPENDENCIES
pom.xml
:
togglz-spring-boot-starter autoconfigures Togglz beans such as FeatureManager, FeatureProvider, StateRepository, UserProvider, ActivationStrategy, etc. (when a developer hasn’t provided them) using @ConditionalOn…… annotations and configuration properties.
4. CONFIGURING FEATURE TOGGLES
FeatureToggles.java
:
application.yml
:
Togglz is enabled by default unless togglz.enabled
is set to false. The configuration keys TEXT_BASED_SEARCH_VIA_ELASTIC_SEARCH
and CONTENT_RETRIEVAL_VIA_CMS
map to the values set in FeatureToggles.java enum.
A disadvantage of configuring the toggles default value in an application’s properties file is when they need to be updated in an environment where there might be multiple instances of the same application running, but more on this later.
5. USING FEATURE TOGGLES
DemoResource.java
:
Using the feature flags is as easy as checking for FeatureToggles.<the enum type field>.isActive() value.
5.1. RUNNING THE DEMO
The output matches TEXT_BASED_SEARCH_VIA_ELASTIC_SEARCH
flag set to active and CONTENT_RETRIEVAL_VIA_CMS
set to false as configured in application.yml.
6. USING FeatureProxyFactoryBean
Let’s see an example where you wouldn’t need to check for FeatureToggles.<the enum type field>.isActive() value.
Let’s assume a legacy and slow service class implementation is getting replaced with an improved one where they both implement the same Java interface, SomeService.java:
SomeService.java
:
OldSomeServiceImpl.java
:
NewSomeServiceImpl.java
:
Let’s configure some @Bean-annotated beans in an attempt to get rid of the if statements which not only reduces the cyclomatic complexity but makes the code more readable:
AppConfiguration.java
:
The interesting part is Togglz’s FeatureProxyFactoryBean proxying between oldSomeService
and newSomeService
beans, both implementing a common Java interface, based on a toogle’s state, FeatureToggles.USE_NEW_SOMESERVICE in this case.
Using SomeService’s proxied bean is simple. someService() method is annotated with @Primary, meaning any autowiring of the SomeService.java interface will use this bean, for instance:
DemoResource.java
(Contd):
Notice no if statement was included.
It’s proxing to the new implementation, NewSomeServiceImpl.java, as a result of the following toggle settings:
FeatureToggles.java
(Contd):
application.yml
(Contd):
Another advantage of the FeatureProxyFactoryBean usage is maintainability, when it’s time to retire the old development toggle there is only one place that would have to change, the removal of oldSomeService() and proxiedSomeService() methods in AppConfiguration.java instead of removing a number of if statements across the application code base. At that point an instance NewSomeServiceImpl.java will be injected when autowiring SomeService.java interface.
7. TOGGLES IN A MULTIPLE INSTANCES ENVIRONMENT
When running multiples instances of an application using feature flags, it would be advisible to store the toggles state in a centralized location where all the instances can read the flags from.
Togglz provides support for a number of implementations:
ArchaiusStateRepository | CachingStateRepository | CassandraStateRepository |
CompositeStateRepository | DatastoreStateRepository | DynamoDBStateRepository |
FileBasedStateRepository | FixedNamespaceStateRepository | GoogleCloudDatastoreStateRepository |
HazelcastStateRepository | InMemoryStateRepository | JDBCStateRepository |
MemcacheStateRepository | MongoStateRepository | PropertyBasedStateRepository |
RedisStateRepository | S3StateRepository | SlackStateRepository |
ZookeeperStateRepository |
You could also provide your own state repository implementing the StateRepository interface.
In any case, you would then define a StateRepository bean which would take precedence over the one autoconfigured by Togglz Spring Boot starter.
8. USE WITH CAUTION
Implementing feature flags using Togglz and Spring Boot can be easily accomplished specially when using togglz-spring-boot-starter custom Spring Boot starter.
Use them with caution though, misusing or abusing development or release feature toggles can lead to a significant technical debt. Toggles might end up in the code and never retired or activated, making the code more complex and fragile, difficult to maintain and requiring more conditional branches to be tested.
Thanks for reading and as always, feedback is very much appreciated. If you found this post helpful and would like to receive updates when content like this gets published, sign up to the newsletter.
9. SOURCE CODE
Accompanying source code for this blog post can be found at: