FunWithFlags: a feature toggle library plus its web GUI as a Plug

Hi @aseigo and thanks for the long and detailed feedback. Also, for your interest in the library :slight_smile:

On your points:

The use of true/false for function parameters (…)

I see what you mean, and if it was a public API I would agree. The Gate struct is a private detail though – it’s not even documented – and users of the library would never see it or use it directly.
Even the web GUI library will only “use” it when rendering the template, but will not create it directly. (of course the tests will create gate structs)

The storage system is using Redis, and the reason appears to be to keep multiple nodes in sync with the flag data set using Redis pub/sub. This is something available out of the box, really, with the BEAM: create a cluster of nodes, send messages between them, end of story. There are even libraries like swarm for rather advanced handling of processes, and Phoenix PubSub for clusterable messaging.

This was a deliberate choice, and I’ve explained the reason in the readme.
To expand on that, I’ve noticed that a lot of web developers and teams moving into Elixir and Phoenix are very cautious about using it in production because the ecosystem is still small, and often the established BEAM approaches don’t work well on more “modern” deploy solutions. Think about PaaS and containers. They have become a staple of modern web development, and directly managing servers and releases is often considered an antiquate practice. Even if you don’t agree, please bear in mind that I’m simply describing what’s common in certain circles.

Developers coming from Ruby on Rails, Python and Django, Node.js, and even Scala and Go are used to package their code or artifacts in a Docker image, Heroku slug or ${INSERT_SIMILAR_TECH_HERE}, and then scale it in the cloud. Telling them that the solution to a problem is to configure a cluster of BEAM VMs will not help, and it’s often not possible: you can’t setup a cluster on a popular PaaS like Heroku, and doing so in Docker is more complex than on traditional servers.

What I aimed for was something that would just work :tm: on any setup.

When someone says “I need a feature toggle system for my 40 Phoenix servers running on Heroku”, I think that answering “Cool, use this library, but you need to add Redis” works better than saying “There is this library, but it won’t work on Heroku”.

is an external (.. slower) dependency really justifiable? Typical applications where I would use this library already have a database, so there is already a persistence end-point available (via Ecto, even..), so it really comes down to needing a way to coordinate changes across nodes, yes?

I think you’re assuming that inter-node communication in a distributed cluster is always going to be faster than a Redis call. It might not always be true but, since I agree that a Redis roundtrip for each call is not ideal, I added the ETS cache :slight_smile:.

With all of this out of the way, the library does provide an internal API for the storage module and the cache-busting pub-sub. I will probably add an adapter for the high-level Phoenix.PubSub module, so that I can ignore the details of the transport (PG2 or Redis); the main reason I haven’t started with that is that I wanted to keep the dependencies to a minimum for the initial version. I also think that someone is working on an Ecto adapter.

Then there is the potential question of more complex gates.

Some other gates are on the roadmap.

If I understand your use cases correctly, I think you can accomplish everything with the abstractions of the library. Just treat them as building blocks instead of complete “fits all” solutions. I’ll send some examples.

I also wondered about how one might do random sampling of users, say on a user sign-up form, to do A/B testing of features.

As I mentioned, a “% of actors” gate is planned. I would be cautious about confusing feature-toggles with A/B testing though. You can use feature toggles for A/B testing if you are confident that the same users will always see the same variant (even when they’ve logged out), but then you need some other way to track user events and perform statistical calculations on the results.

I suppose one way to get there would be to have a function that sets up the state in the session, then the defined flag would (via a FunWithFlags.Group protocol) pick out the state as setup in the current session. If that became a more common usage pattern, would you consider adding some convenience API for this in FunWithFlags, or would that be out of scope in your view?

You’re describing an A/B testing tool, and I’m not sure about adding support for this use case to the library. If %-based gates ship, however, they can be used as building blocks for an A/B testing framework I think.

3 Likes