Using Feature Flags in Java (and Spring Boot)

Umer Mansoor Umer Mansoor Follow Nov 22, 2020 · 9 mins read

Feature flags or feature toggles are a powerful technique to release new features and are quickly becoming a key part of modern software development.

Feature Flags allow developers to launch features to production so that only internal teams can see them, but keep them hidden from users until they are ready. This allows faster iterations and production testing with the peace of mind. When everything looks good, features can be gradually rolled out to real users to minimize risks even further. And if any errors are discovered later, easily rollback or disable with just a click of a button without any code changes or redeploys.

I’ve been using feature flags for the last 5 years and find them to be an incredibly powerful technique to launch features quickly and confidently to millions of users. I have even released partial changes to production to get quick feedback without worrying about breaking anything!

In this post, we’ll see how to use feature flags in Java and Spring Boot. Let’s get started.

Challenge

Suppose you’re a software developer working on a backend service: User Profile. There is an API that returns user information from the database, combining it with information retrieved from some other services and sources. One day, you were reviewing the performance of the API and noticed it is very slow and takes up to a second to return response.

After some investigation and find the root cause. The delay is being introduced due to the way the service calls other services to get user’s status, open orders and pending cancelations: the calls are being made sequentially, that is, one after the other. You think you can improve the performance by parallelizing the calls.

In traditional software development, you’d create a new feature branch e.g. feature/JIRA-101-async-calls-in-user-profile. You’d make your code changes and keep committing to this branch. When everything looks good, you’d open a pull request to merge into the development branch. You’d do some more QA and performance testing the QA environment. Finally, your code will be merged into the main branch and your feature will go to staging and then to production. If you find any issues in production, you’d have to create a hotfix into main directly to rollback your changes.

Sounds stressful. If you think about the change you’ve identified, i.e. making asynchronous calls, it is not complicated. But the way software releases are done in large enterprises and the risk of breaking something even with a small change and impacting millions of users, there’s a lot of added friction and stress.

Enter feature flags. Let’s see how we’d utilize feature flags to solve performance issues and release with the peace of mind.

  1. Create a new feature flag. Turn it off for everyone except yourself. You can do by user id, by environment, or any other criteria.
  2. Create a new method which makes asynchronous calls to other services.
  3. In the main method, check if the feature flag is on. 3a: If the feature flag is on: call the new method which makes async calls 3b: If the feature flag is off: Call the old method that you’re trying to replace.
  4. Enable the feature flag in the QA environment. This will allow everyone using the QA environment to see your changes and test them.
  5. Merge into the main branch if everything looks good. Enable the feature on your staging environment. Enable it for all internal teams in production but keep it hidden from your users.
  6. Compare the performance (API response time) of your change to the old API. If everything looks great, gradually roll out the feature to real users.

Let’s see how we can do these steps and use feature flags to release our code to production quickly and confidently.

Solution

1. Set up Feature Flag

Head over to https://app.unlaunch.io/signup and create a new account if you haven’t already done so. Unlaunch is a free feature flag service with strong support for Java. As part of account creation, you’d be asked to create a new project. A project is a collection of related feature flags. If you use microservices or SOA, you’d create a new project for each microservice. You can also use projects to organize by teams in the case of monoliths.

In this example, we’ll create a new project called “User Profile” as part of registration. By default, each project gets two environments: Production and Test. To keep things simple for this example, we’ll do all work in the Production environment. But separate environments allow you to test changes to feature flags independently.

Make sure that the Production environment is selected using the dropdown on the top left corner of the sidebar.

Unlaunch Console Figure 1 - Unlaunch Console

Next up, create a new feature. Follow the screenshot below. Here, we create a feature flag with two variations: on and off. In our code, we’ll check this flag. If on variation is returned, we’ll show the new feature (i.e. call the new method we just implemented.) Otherwise, we’ll hide the feature (i.e. use the old code.)

new feature flag Figure 2 - Create a new flag

Next, we’ll enable the feature flag, that is, serve the “on” variation to only a single user for now. For everyone, else, we’ll serve the “off” variation. Please make sure your setup looks similar to the screenshot below. Also, don’t forget to enable the flag by clicking the green “Enable Flag” button.

Turn the feature flag on for one user id Figure 3 - Turn the feature flag on for user id [email protected] only

At this point, the flag setup is complete. Let’s take a look at how we’d set up the SDK to call this flag and show the new feature.

2. Call Feature Flag in Your Application

Now, let’s use this feature flag in our Spring Boot service to determine whether to use new or old algorithm.

Note: If you are looking for a plain Java example, please see to this repo.

First, add the Unlaunch Java SDK dependency in your pom.xml (or build.gradle)

<dependency>
	<groupId>io.unlaunch.sdk</groupId>
	<artifactId>unlaunch-java-sdk</artifactId>
	<version>0.0.5</version>
</dependency>

Next, you’ll need to provide the SDK key to connect to your Unlaunch project and environment. You can find the SDK key for your environment by clicking Settings in the sidebar. Choose the Server Key for the Production environment.

new feature flag

You can paste the SDK key in your application.yaml or make it available as an environment variable export UNLAUNCH_SERVER_KEY=<paste server key here>.

unlaunch:
  server:
    key: PASTE_SERVER_KEY_HERE_FROM_SETTINGS

2a. Initialize the Unlaunch Client

Next, we’ll create and initialize the UnlaunchClient as a bean. When you initialize UnlaunchClient, it will download all feature flags in memory. All evaluations will be done against in memory data store (e.g. HashMap) and are really fast.

@org.springframework.context.annotation.Configuration
public class Configuration {
    @Value("${unlaunch.server.key}")
    private String sdkKey;

    private static final Logger logger = LoggerFactory.getLogger(Configuration.class);

    @Bean
    public UnlaunchClient unlaunchClient()  {
        UnlaunchClient client = UnlaunchClient.builder().
                sdkKey(sdkKey).
                pollingInterval(30, TimeUnit.SECONDS).
                eventsFlushInterval(30, TimeUnit.SECONDS).
                eventsQueueSize(500).
                metricsFlushInterval(30, TimeUnit.SECONDS).
                metricsQueueSize(100).
                build();

        try {
            client.awaitUntilReady(2, TimeUnit.SECONDS);
            logger.info("unlaunch client is ready");
        } catch (InterruptedException | TimeoutException e) {
            logger.warn("client wasn't ready " + e.getMessage());
        }
        return client;
    }
}

2b. Evaluate the Flag to Choose New or Old Algorithm

Then in the UserService class, let’s decide whether to use the new algorithm or not.

@Service
public class UserService {

    @Autowired
    private UnlaunchClient unlaunchClient;

    public User getUserById(String id) {

        // Evaluate the feature flag
        String variation= unlaunchClient.getVariation("implement-async-calls", id);

        if (variation.equals("on")) {
            // Call the New algorithm if the flag returns: on
            return newAlgorithm(id);
        } else {
            // Call the Old algorithm if flag returns: off
            return oldAlgorithm(id);
        }
    }
}

One note: The getVariation(...) method will never throw an exception or return null. If there is an error such as if the flag is not found or the initial sync fails, it will return a special String value: control. So you don’t have to worry about adding any additional error or checks around this method and can safely use it everywhere.

3. Try it out

You can find the complete source code for this project on GitHub. You can clone and run it locally using mvn spring-boot:run or (gradlew bootRun).

To test the feature flag, call the API with any user id e.g. [email protected]. Because we disabled the flag for all users except [email protected], the old algorithm will return. http://localhost:8085/api/v1/users/[email protected]

new feature flag

Now let’s call the same API with [email protected] which should return the on variation and hence the new algorithm. (See Figure 3.) http://localhost:8085/api/v1/users/[email protected]

new feature flag

That’s all. If you enjoyed this post, please share it.

#featured #feature-flags

You May Also Enjoy


If you like this post, please share using the buttons above. It will help CodeAhoy grow and add new content. Thank you!


Speak Your Mind