I’ve been a GitLab member for 3 years now, but became a GitLab staff member in January 2019. It’s be a whirlwind year so far. Working for a hot startup moving at this pace has been the biggest change I’ve had to experience since moving to Ontario. It’s been exciting and wonderful, but that’s tangential to what this is about. At GitLab, I work on the release team, and a big area I focus on is FEATURE FLAGS!
Feature Flags… what
Feature flags, if you haven’t had the opportunity, can be a big part of continuous delivery. Martin Fowler loves them, and GitHub Actions featured them.
At GitLab, our feature flag implementation is compatible with Unleash, and
we are compatible with any of the clients that support unleash. However, my
favourite functional language wasn’t compatible! There was no
unleash-client-elixir
, but after 7 months of learning the deep intricacies of
feature flags and working up the courage to actually release something, there
is!
unleash_ex
This is my first elixir project that has made it to any sort of usable state. I’ve been trying to build a few phoenix applications as I come up with ideas for them, but learning phoenix AND elixir (and brushing up on my general backend skills) was a tad overwhelming, so unleash gave me something simple to focus on and get my language basics down.
There are well-kept docs for specifications, so I thankfully didn’t have to implement things blindly or reverse-engineering another client implementation. There are also client specification tests that can be implemented to give me confidence that my code was correct.
Design
This has given me some good digging into what makes a great elixir library, and about what the ecosystem brings to the table, including the glorious OTP.
OTP Goodness
An OTP application starts that will poll the configured server for feature
flags. A GenServer
starts to maintain the state of the feature flags as
received from the server, and one starts to capture metrics, sending them
periodically.
Extension
Each strategy is implemented in its own module, using a module that adds some
logging around the check as well as ensuring the strategy implements the
interface correctly. A tuple of the pattern {result, map}
is expected, the map
contains relevant details, computed or otherwise, to be logged out. An example:
defmodule MyApp.MyStrategy do
use Unleash.Strategy
def enabled?(params, context) do
# do work
{true, params}
end
end
An example map from userWithId
that is used to put relevant details in logging:
%{user_id_list: list, user_id: user_id}
This results in a log line of the following:
UserWithId computed true from user_id_list: 1,2,3, user_id: 2
By comparison, if a simple true
/false
is returned, the log line is simply:
UserWithId computed true
That doesn’t really doesn’t tell anyone much, so I strongly encourage the first use.
To use your new strategy, you must configure the library to use a new module that can list all the available strategies, including yours:
defmodule MyApp.Strategies do
@behaviour Unleash.Strategy
def strategies do
[{"myStrategy", MyApp.MyStrategy}] ++ Unleash.Strategies.strategies()
end
end
# config.exs
config :unleash, Unleash, strategies: MyApp.Strategies
Improvements
As with all things software, “finished” isn’t exactly a state of any project. There are a few tasks that I think would improve use of the project:
- Move away from
Config
.Config
andMix.Config
count as an anti-pattern when building a library, even though only 1 instance ofunleash
shold probably be used per application.- I’m thinking of injecting configuration through application initialization,
and probably storing that in an
Agent
for easy retrevial later.
- Write more tests.
- While is nothing to scoff at (64% at
the time of writing, hopefully it’s gone up since then), I can do better,
and there are some areas that I’m very unsure about. The
GenServer
and OTP areas, specifically.
- While is nothing to scoff at (64% at
the time of writing, hopefully it’s gone up since then), I can do better,
and there are some areas that I’m very unsure about. The
- Keep up to date with Unleash.
- Unleash itself is a moving project, so I’ve signed up to keeping up with it. I can’t promise to be fast, but I can try my best!