Open/Closed principle on the example of Togglz Java library + Spring Boot
1. Introduction. Push your commits directly to prod? Why not, Togllz for the rescue!
Once in my developer consultant career I worked in a team that follows extreme programming methodology. The team has built a CI/CD pipeline utilizing the benefits of trunk-based development on a single Git branch. Their fast code delivery practices rely on teammates’ common understanding that a developer should be able to push their code to the main branch without much hesitation, being confident that a code piece would not appear in production servers before it’s been quality checked. An automated test suite in CI/CD pipeline, which sufficiently covers systems’ behavior, assures that new changes to the code-base will not bring bugs. Nevertheless, not every commit pushed to the code repository is intended to go live as soon as possible. There are situations when a feature needs manual approval, manual QA-ing, or when it is expected to start running in production servers only at some specific time. In such cases feature toggles were found handy.
I started using a java library called Togglz last year and so far happy with what it offers. It’s a relatively simple java library, which implements various ways of toggling features in your code. I found the library easy to integrate into a Spring-managed project. Besides, Togglz comes with an extension, ready-to-use web GUI. But what I value in this library more than everything it offers is its openness for customization. A developer using Togglz can tune its functionality using instruments shipped together with the framework or bringing in their own self-written pieces of code. For example Feature toggles’ states (on/off) can be loaded from Spring property files, JDBC data source, DynamoDB table, etc. I am leaving “etc.” here as the implementations of Togglz’ StateRepository interface that I’ve touched and found useful for my projects are the previously mentioned ones. However, the library offers a variety of its own implementations for StateRepository, an interface that you can implement yourself if you wish and as you wish. The same applies to other interfaces of Togglz: you can substitute default functionalities of the library with your own without much hustle. I believe this came true because object oriented design rules lying behind the famous acronym SOLID was well followed:
- Single-responsibility. Interfaces inside of Togglz mechanism are assumed to trigger simple tasks.
- Open/Closed principle. The core functionality of the library doesn’t need to be changed in order for it to be customized. We will stop on this one in particular.
- Liskov substitution principle. Classes ensuring the whole feature toggling business can be easily substituted with their subtypes.
- Interface segregation. Many simple task performing small interfaces are provided to collectively maintain the whole feature toggling business.
- Dependency inversion. The core functionality of the library does not depend on the specifics of interface implementations meaning various implementations can be injected into the framework.
2. Building a simple spring boot application.
To demonstrate the features provided by the library and possibilities to extend them, I created a simple spring boot application that just says hello via rest API.
A rest controller that calls a HelloService:
And the service, which is quite basic, simple enough, just returns its hello:
After an ordinary spring boot deployment our application starts handling HTTP requests:
As part of our next task let’s imagine we want to make the HelloService to speak some other language, for example, Kazakh (“Hello world” in Kazakh would be “Sálem Álem”). Additionally, the task has a requirement saying that the application maintenance team wants to be able to switch the language at their will without needing to redeploy the application. It sounds like a good reason to try out Togglz library.
3. Integrating Togglz library into the application. Basic app feature.
Few configurations are needed to bring Togglz into the project and enable its GUI to toggle and monitor application features. In the following demo project features are represented in the code as java enumeration values. The framework is to persists the features’ state in a relational database.
First things first. The maven dependencies to bring Togglz and the Togglz UI into our project:
Next we want to setup a property-file sourced by spring. The following lines are there to enable the Togglz console. Its GUI console has its own security mechanisms, which I ignored for this post’s scope. Besides the Togglz security, it’s also possible to use spring security module to configure access to the Togglz web console.
A Spring Java configuration defining beans needed for the library to function. The most important bean here is featureManager of type org.togglz.core.manager.FeatureManager, which is dependent on other two beans.
The org.togglz.core.spi.FeatureProvider instance is initialized as org.togglz.core.manager.EnumBasedFeatureProvider and uses the following enum as representations of feature names:
So far we have only one lonely feature to toggle on and off. Note that the enum has to extends org.togglz.core.Feature class.
To store states of feature toggles I chose org.togglz.core.repository.jdbc.JDBCStateRepository implementation coming from Togglz package, which is expecting and depending on javax.sql.DataSource configured for an underlying SQL database. Besides, many different implementation classes of org.togglz.core.repository.StateRepository interface are shipped in the jars we’ve already imported to the project:
I’ve used extensions of the library that make it possible for Togglz to store the feature states in NoSQL databases as well (e.g. AWS DynamoDB). However, this time we use a relational database as an example.
Querying the data from the DB:
I place the feature toggle in the service class. Note, as usage of the featureManager becomes part of the application’s functionality, it’s important to test both states of the feature: when it’s toggled on and off.
Let’s see how the toggle can be turned on. It’s done pretty easily actually. One mouse click sends an HTTP request, which is automatically handled and persisted by Togglz.
…aaand it’s on.
DB’s state should change as well as the color of the button on UI. Since the data is saved in the database application restarts will not make it forget that feature is enabled.
The changes can be noticed in the app’s behavior:
4. Feature activation strategies. Time based toggling.
Now, let’s imagine that as their next request, people maintaining the app ask you to toggle the feature on and off automatically, based on time. To support this kind of feature toggling activities Togglz has got its built-in activation strategies, accessible directly from the web UI.
I chose the ‘Release date’ activation strategy and entered the release date I wanted in the text-boxes appeared below:
The params are reflected in the feature state repository. You could notice the columns called “strategy_id” and “strategy_params”.
What I appreciated about the activation strategy mechanisms in Togglz is the fact that the params for different strategies have a generic form of storage. How is it even useful for a developer? For answering this question let’s imagine another situation. Time passes and now our lovely maintenance team wants the feature to be enabled automatically every day, but only during certain day hours. And again, it’s expected to be possible to change the activation time without needing to redeploy the server or touch the codebase. We’re lucky that we already have Togglz in place. Thanks to the unified format of inputting parameters in the UI, and the generic way of how they’re stored in StateRepository, and the way they’re handled by the framework, developers can use this entire mechanism for building their own custom activation strategies. So let’s experience some openness for extension principle, which means extending the library’s features without even touching its source code.
5. Extending the library. Building a custom feature activation strategy.
Our custom activation strategy should extend an interface called org.togglz.core.spi.ActivationStrategy.
Note that we’re obliged to implement methods of the ActivationStrategy parent class. Those methods are needed by the framework to display strategy’s parameters on the GUI, and . Obviously, we also are expected to handle these parameters in isActive() function, which is declared as a method returning a boolean value. Some parameter validation is recommended in the method, but I don’t want to over-complicate the example code.
Activation strategies are wired into an activationStrategyProvider bean, which is itself a dependency of the featureManager bean:
The results of this exercise can be immediately seen on the web GUI. We set the parameters to the desired values so that app can practice speaking Kazakh 2 minutes a day from 19:25 to 19:27 Zulu time:
And consequentially the parameters are reflected on the underlying database’s state:
So that’s it. Following simple steps, we managed to configure and customize Togglz library. While doing so we have not touched the insides of the library, because it is closed for a modification. However, it was possible to add additional functionality to it as it was open for extending it. What I’d like to highlight here is that if you design your application/library in a way that dependencies are externally injected into your classes, and if you provide possibilities for the dependencies to be easily substituted by their different implementations (Liskov substitution principle), and if the library stays open for someone extending it, then, as a result, your code will become one pleasant code piece to use and tune. In my opinion, Togglz is a good example of a simple lightweight library, whose authors followed the SOLID principles when designing their APIs. I would defintely recommend it to friends.
7. Useful links
- Togglz web site: https://www.togglz.org/
- Togglz source code: https://github.com/togglz/togglz
- Demo application source code: https://github.com/SagynyshBaitursinov/togglz-demo