Flips: Feature Flipping for Java
Posted on October 7, 2017 • 5 minutes • 924 words
Table of contents
Flips is an implementation of the Feature Toggles pattern for Java and Spring (Spring Core / Spring MVC/ Spring Boot) based application. Feature Toggle is a powerful technique that allows teams to modify the system behavior and deliver new functionality to end-users rapidly and safely.
Why Another Library for Feature Toggles?
The idea behind Flips is to let the clients implement toggles with minimum configuration and coding.
The main motivations behind implementing this library were:
- Should be simple to use
- Should require minimal configuration and code
- Should be able to flip a feature based on various conditions
- Should be able to flip a feature based on a combination of different conditions
- Should be possible for the clients to create custom conditions to suit their requirements
The library Flips works with Java 8 and Spring Core/Spring MVC/Spring Boot, and is available for web and non-web applications.
What Does Flips Offer?
The library Flips provides various conditions to flip a feature. The image below summarizes the features:
Any feature can be flipped ON or OFF based on different conditions that can be value of a property, current active profiles, days of the week, or a combination of these, etc. Let’s get started with in-depth understanding of these features.
Getting Started
Include the necessary dependency:
<dependency>
<groupId>com.github.feature-flip</groupId>
<artifactId>flips-web</artifactId>
<version>1.0.1</version>
</dependency>
Or,
<dependency>
<groupId>com.github.feature-flip</groupId>
<artifactId>flips-core</artifactId>
<version>1.0.1</version>
</dependency>
Detailed Description of all the annotations
The library Flips provides various annotations to flip a feature. Let’s have a detailed walk-through of all the annotations:
@FlipOnEnvironmentProperty
@FlipOnEnvironmentProperty
is used to flip a feature based on the value of an environment property.
@Component
class EmailSender {
@FlipOnEnvironmentProperty(property = "feature.send.email",
expectedValue = "true")
public void sendEmail(EmailMessage emailMessage) {
}
}
@FlipOnProfiles
@FlipOnProfiles
is used to flip a feature based on the environment in which the application is running.
@Component
class EmailSender {
@FlipOnProfiles(activeProfiles = {"dev", "qa"})
public void sendEmail(EmailMessage emailMessage) {
}
}
The feature sendEmail
is enabled if the current profile (or the environment) is either dev or qa.
@FlipOnDaysOfWeek
@FlipOnDaysOfWeek
is used to flip a feature based on the day of the week.
@Component
class EmailSender {
@FlipOnDaysOfWeek(daysOfWeek = {DayOfWeek.MONDAY})
public void sendEmail(EmailMessage emailMessage) {
}
}
The feature sendEmail
is enabled if the current day is MONDAY.
@FlipOnDateTime
@FlipOnDateTime
is used to flip a feature based on date and time.
@Component
class EmailSender {
@FlipOnDateTime(cutoffDateTimeProperty = "default.date.enabled")
public void sendEmail(EmailMessage emailMessage) {
}
}
The feature sendEmail
is enabled if the current datetime is equal to or greater than the value (in ISO-8601
format) defined by the default.date.enabled
property.
@FlipOnSpringExpression
@FlipOnSpringExpression
is used to flip a feature based on the evaluation of a Spring expression.
@Component
class EmailSender {
@FlipOnSpringExpression(expression = "T(java.lang.Math).sqrt(4) * 100.0
< T(java.lang.Math).sqrt(4) * 10.0")
public void sendEmail(EmailMessage emailMessage) {
}
}
The feature sendEmail
is enabled if the expression evaluates to TRUE. This annotation happens to be one of the most powerful annotations in the Flips library. Why so?
One could always write a custom spring component and use the same in @FlipOnSpringExpression
to flip a feature.
@FlipBean
@FlipBean
is used to flip the invocation of a method with another method defined in a different bean.
@Component
class EmailSender {
@FlipBean(with = SendGridEmailSender.class)
@FlipOnProfiles(activeProfiles = "DEV")
public void sendEmail(EmailMessage emailMessage) {
}
}
This will flip the invocation of the sendEmail
method with a method (having same signature) defined in the SendGridEmailSender
Spring component if the current profile is DEV.
@FlipOff
@FlipOff
is used to flip a feature off.
@Component
class EmailSender {
@FlipOff
public void sendEmail(EmailMessage emailMessage) {
}
}
The feature sendEmail
is always DISABLED.
Combining annotations
@Component
class EmailSender {
@FlipOnProfiles(activeProfiles = "dev")
@FlipOnDaysOfWeek(daysOfWeek={DayOfWeek.MONDAY})
public void sendEmail(EmailMessage emailMessage) {
}
}
The feature sendEmail
is enabled if the current profile is dev AND the current day of the week is MONDAY.
Import Flip Context Configuration
To bring all Flips-related annotations into effect, one needs to import FlipContextConfiguration
or FlipWebContextConfiguration
.
@SpringBootApplication
@Import(FlipWebContextConfiguration.class)
class ApplicationConfig {
public static void main(String[] args) {
SpringApplication.run(ApplicationConfig.class, args);
}
}
Please refer to the sample application config here .
Creating Custom Annotations
All the annotations provided by the library are of type @FlipOnOff
, that is essentially a meta-annotation. So, it is possible to create a custom annotation annotated with @FlipOnOff
at the method level:
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@FlipOnOff(value = MyCustomCondition.class) !!Important
public @interface MyCustomAnnotation {
}
As a part of this annotation, specify the custom condition that will evaluate this annotation.
@Component
public class MyCustomCondition implements FlipCondition {
@Override
public boolean evaluateCondition(FeatureContext fContext,
FlipAnnotationAttributes attributes){
//code to evaluate flip condition
return false;
}
}
This Condition class needs to implement FlipCondition
and MUST be a Spring Component.
That is it! You can use your custom annotation to any method to flip it ON or OFF based on your condition.
What is FeatureNotEnabledException
The exception FeatureNotEnabledException
is thrown if a disabled feature is invoked. In case of a web application, one could the use flips-web
dependency, that also provides a ControllerAdvice
to handle this exception.
It returns a default response and a status code of 501, which can be overridden. Please refer to the sample project
for more information.
Wrap Up
We believe the MVP is done and features like flipping at runtime and supporting database-driven feature flips are in the pipeline.
For any custom flip condition, one could go ahead and use @FlipOnSpringExpression
with your custom spring bean to determine the flip condition.
If you want to have a look at the code or even want to contribute, you can check out Flips
.
Feel free to share any feedback.