How we implemented feature flagging with Split.io

Illia Kaplaushenko
Getsafe
6 min readJul 21, 2021

--

One of the core values of Getsafe is excellence. That’s why we aim to constantly deliver great features to our customers and iterate on them to make them as good as possible. To do this we take what will be a big feature and split it into smaller valuable and fully working parts and then release each part to customers. After that, we collect feedback and adapt the feature to the user’s needs. It allows us to be more flexible and always provide the best solutions. We realised that feature flags are a great tool to enable us to iterate more effectively. In this article, I want to share how we set up Split.io as our tool of choice.

Why feature flags?

Feature flags allow enabling or disabling some parts of the UI depending on different conditions, such as environment, target group, or defined percentage of users. We also find them useful for collecting more feedback about the user experience which we then use to refine our app. Additionally, feature flags allow developers to continuously deliver features and keep the main branch clear and ready to be released without breaking the production app. The flexibility to roll out the change to limited groups of users gives us the confidence to release quickly and in case of a problem, we can disable it again so the app keeps working.

Why Split.io?

The main challenge was to find an appropriate tool that allows us to easily manage feature flags and environments, allocate the traffic by different conditions, and most importantly set groups of users by unique identifiers or email patterns.

We decided that Split.io together with Redux SDK met all our needs for both React web and React Native mobile applications. It has all the benefits that we need: setting up feature flags and environments, defining groups of customers and splitting traffic into a defined percentage.

How we set it up

First, we added Split.io’s Redux SDK to our project:

yarn add @splitsoftware/splitio-redux

We prefer to store all data related to Split.io in one folder, so our file structure looks like this:

app/store/services
└── featureFlags
├── controllers.js
├── selectors.js
└── constants.js

The next step was adding the splitReducer provided by SDK to our existing reducers:

The schema of the splitio state is the following (with some explanatory comments):

Here I’d like to clarify some terminology used in the schema. Split means a part of the functionality and any roll out plan associated with it. Mostly we are referring to feature flags. Treatment means variations of a feature. By default Split.io uses “on” and “off” for enabling and disabling a feature respectively, but you can use a custom naming.

There is another field that belongs to the treatment called config . Split.io allows passing a custom config associated with the treatment. We haven’t used this feature yet, but it allows to be even more flexible when defining variations of the feature flag. According to the documentation you can use it for example, to set a colour or a size of elements, define different copy for each treatment.

The next step was to create a function that would initialise our Redux SDK. For doing this you need to install and set up the ReduxThunk middleware. Redux SDK provides us the initSplitSdk action creator that returns a thunk action. We wrote the init function in controllers.js that dispatches this action and therefore initialises the Redux SDK.

There are two important parameters in the config that we had to pass to the initSplitSdk: authorizationKey and key. The first one is different for each environment and can be obtained for your organisation as described here.

The second parameter key is used for uniquely identify a user in Split.io. This is the very important part of our setup. Split.io’s Redux SDK has to be initialised with a unique key. But then it allows passing another one while fetching split’s treatment data. In our setup we decided to initialise the SDK with the device unique id but then after logging in we re-fetch treatments again and provide more relevant userId for explicitly identifying users.

As mentioned above, defining groups of users is an important use case for us. We usually use data such as an email, an email pattern or even a list of purchased products. Using this data, we created a group of internal users that has early access to some features not yet enabled for customers. To do this we needed to provide a list of additional attributes while fetching the treatments.

We created the fetchAllTreatments function in controllers.js. It dispatches the getTreatments thunk action provided by the SDK. This action accepts a configuration object with the following fields:

  • splitNames — a list of all splits that we defined in constants.js (for simplifying I’ve shown it as a part of this file in the code snippet below).
  • key — as described above, a key that we used for identifying a user (device unique id or userId).
  • attributes — a list of additional data that we used for defining groups of users.

After configuring the SDK we only needed to initialise it and fetch all treatments afterwards. We did it in the initApp function that we use for dispatching different actions when the app is being launched:

By this moment the SDK should be initialised with the device unique id because the current user hasn’t been authenticated yet. But remember that our goal was to identify a user by the userId and additional attributes. We needed to re-fetch a list of treatments again after the user’s authentication and fetching all initial data:

So the main part of the setup was done. We had two important things left: create our first feature flag in the Split.io and use it in the app in a component. We went to the Split.io’s dashboard and selected the tab “Segments”. Here we configured a segment of users, for example, a list of employees for internal testing. As we used userId for identifying a user, we added it to a list as shown below:

Setting up a segment of users

In the “Splits” tab we created our first split. First, we needed to define a list of treatments for the split. By default, it is either “on” or “off”.

Define values for the treatment

Then we set a whitelist for a treatment based on segments of users that we had already defined above:

Creating a whitelist for a segment of users

Finally, we set different targeting rules based on attributes passed to the SDK. That’s how we achieved the goal to roll out a feature for a limited group of users for keeping the production app clean.

Targeting rules based on custom user’s attributes

The last part of the setup was to use this split in the app. We decided to go with selecting a treatment value from the state and then map it to properties in a component. I’m going to show you a simplified usage of the split created above.

First, we created a selector for our treatments. We used the selectTreatmentWithConfig from the Redux SDK which returns not only the treatment’s value, but also the custom config attached to it. This makes our setup easy to extend when we’ll have a use case with the custom config.

Then we used this selector and mapped the treatment’s value to the component’s props:

Conclusion

So here I’ve shown you a basic setup of the Split.io together with the Redux SDK. Of course, it has a lot more useful settings not highlighted in this article such as splitting traffic with a defined percentage, different tracking options and measurements. But even this implementation has improved the development process and had a huge impact on customer satisfaction. We at Getsafe already can see that the usage of feature flags together with Split.io has improved the quality of our product and allowed us easily adapt to the needs of our customers. And this is considered to be crucial for achieving excellence. If you are excited about what we are doing and you want to be a part of this journey check out our job openings and apply!

--

--