Feature Flagging in Elixir with FunWithFlags
Feature flags are an indispensable tool of modern software engineering. Start using them easily in Elixir thanks to @tompave's FunWithFlags.
Feature flags are an indispensable tool of modern software engineering. But having to implement them myself isn't usually my idea of fun.
When picking a feature flagging solution you want something that is easy to integrate into your existing stack, and is simple and reliable to use.
If you're using Phoenix and/or LiveView, you're in luck! We happen to have a great option in the ecosystem.
Before we get into it though...
Why use feature flagging?
Feature flags allow you to control rollout of new functionality in a targeted way. If the flag isn't enabled for a given user, they don't see the functionality.
You could roll this out user by user if you wanted to.
This allows you to merge code in before it's feature complete. The ends user doesn't end up seeing or being impacted by the changes until you want them to be.
This means that you can get little changes into the mainline branch all the time, ideally multiple times per day (practicing continuous integration, and/or trunk based development).
What tools are available?
If you're operating in a microservice architecture you may want to reach for a tool like LaunchDarkly.
But if you've got an Elixir application built on Phoenix, especially a LiveView application, you don't need to reach outside the Elixir ecosystem.
Thanks to Tommaso Pavese (@tompave on GitHub) we've got the fantastic library FunWithFlags
. It gives you almost all of the functionality that you'd want in a feature flagging implementation.
What does FunWithFlags
provide?
FunWithFlags
works really well if you don't have a lot of budget and are running a side project or an early stage startup. Or if you just don't want to take on the additional complexity of integrating a third party vendor.
By installing a package (or two) you get the following:
Boolean feature flags
The simplest form of feature flagging. Either the functionality is turned on or off for the entire user base.
Actor based feature flags
Not to be confused with the actor model, actor based feature flags are ones that are controlled for a given entity using a unique ID. These can be user IDs, account or organization IDs, or any other uniquely identifiable entity.
Group based feature flags
Similar, but slightly different from the above, group based feature flags allows you to have specific named groupings across your application that can be used to control functionality.
Technically this could also be implemented using the actor feature flags, but this sends different messages about intent to you the user.
Percentage of time based feature flags
Some normally distributed percentage of the time, functionality will be enabled for user.
This is not static by user, so if you were implementing a new checkout gated behind the percentage of time flag a user may see the new checkout on one page load and the older version, or no checkout, on another page load.
Percentage of Actors feature flags
Some normally distributed percentage of an actor base will have a given feature enabled.
Unlike the percentage of time, this is a deterministic check. So taking the above example, the same user would either always see the new checkout, or always see the old, while this feature flag is in play for them at a given enabled percentage.
An administrative UI
Out of the box it ships with a simple, but solid, admin UI via FunWithFlagsUI
.
Deep Elixir integration
As an Elixir package, you can poke around under the hood, and leverage some of the underlying data structures if you need, in order to extend the functionality.
For example, you could build out a REST or GraphQL API endpoint in order to get the relevant feature flags that are enabled for a user.
You could do this either using the interface FunWithFlags
provides, or by reaching into the internals and calling the Redis or Ecto stores and serializers directly.
What you don't get
It likely won't scale as well as LaunchDarkly depending on your team's skills and ability to diagnose and troubleshoot issues as load grows. Depending on your needs this may or may not be a relevant problem.
Regardless of your team's skills, it's another piece of the tech stack that you own and have to maintain, which may not be something you want to take on.
An HTTP API
You don't get an HTTP API out of the box, so going back to a microservices environment, you'd have to roll your own API endpoint.
It probably wouldn't be too much of a lift, because you already have access to all of the data structures and Elixir APIs that you could wire up to a Phoenix API either via GraphQL or REST, but this is something you should know up front.
Baked in support for experimentation
The biggest thing missing from FunWithFlags
that something like LaunchDarkly ships with is baked in experimentation instrumentation and visualization functionality.
For example if you're testing if Version A of a feature outperforms Version B, you have to instrument all of that, gather the data, and compare it yourself. There isn't any integrated support.
This is something you can do with Telemetry, and something like Prometheus and Grafana, but it's always nicer when you don't have to build this functionality yourself. It could be worth upgrading for.
Why not roll your own?
Most of the time you'll want to start with just simple global booleans, which is great, but you'll likely at some point want to be able to enable different features on a user by user basis, or some other grouping in your application, or on a percentage basis.
Implementing all of this is a pain, and not your core business.
If there weren't a nice open source solution in the ecosystem I'd recommend you go purchase something.
But given that in the Elixir ecosystem we have FunWithFlags
, I'd recommend you at least start your investigation there. It can serve as a starting point towards where you need to go. Especially as an early stage startup or indie developer.
Wrapping up
If you're currently struggling, or have discovered any neat workflows, with feature flagging in Elixir I'd love to hear more. You can reach me via email at brittonbroderick@gmail.com.
Alternatively, if you're interested in building out experimentation support for FunWithFlags
, reach out as well, because while I don't have the time to lead that effort currently, I'm interested in trying to assist the effort.
Same email address as above.