Where do feature flags belong?

So I am building a feature flag solution in my company. This aims at hiding/changing the results of some user actions depending on wether some flags are set.

The flags will be saved in the DB. I can’t change that.

My question is simple: should I allow the use of feature flags in the core of my app? Or should I only allow them to be used in the interface?

My guess is that my core should be agnostic from flags but after all, feature flags are part of the business logic, aren’t they?

Example : Should I use flags like this (without them in the core):

  def index(conn, _params) do
    my_resource = case FeatureFlag.enabled?("my_flag", get_session(conn)) do
      true -> MyAppCore.new_implementation
      false -> MyAppCore.old_implementation
    end
    render(conn, "index.html", resource: my_resource)
  end

Or with flags used in the core:

  def index(conn, _params) do
    my_resource = MyAppCore.my_implementation(get_session(conn))
    render(conn, "index.html", resource: my_resource)
  end

function in the context :

  def my_implementation(session) do
    my_resource = case FeatureFlag.enabled?("my_flag", session) do
      true -> new_implementation
      false -> old_implementation
    end
  end
4 Likes

This is a personal style choice, but I prefer to keep business logic out of controllers and use pattern matching. I guess this depends on what patterns already are the norm in your app.

  def index(conn, _params) do
    enabled = FeatureFlag.enabled?("my_flag", session)
    my_resource = MyAppCore.my_implementation(enabled get_session(conn))
    render(conn, "index.html", resource: my_resource)
  end
  def my_implementation(true session) do
    new_implementation
  end
  def my_implementation(false, session) do
    old_implementation
  end
1 Like

Or you can pass the flags from the controller to the core as options. So the core stays functional but supports those options.

edit: well I misread @mpope post, because I am actually saying the same thing. So +1 for that.

1 Like

Thank you for sharing your view on this !

After some thought I’m leaning toward keeping any feature flag logic away from the core. Only functions to enable/disable/check flags would be in the core.

My main point being the following : if I have a web client and a mobile app client, if I put some flags logic in the core, it will make things more complicated if I want to use only flags in one of my clients.

Your solution with adding a enabled boolean argument in my core function would be quite clean, but I could even get rid of it if I only maintain feature flags logic in controllers for example.

The only drawback, if it is really one, is that it would make my controllers fatter. But is it really an issue?

1 Like

I know this a little off topic, but FWIW have a look at FunWithFlags. It may help you in other areas etc.

1 Like

Since you’re pushing alot of your business logic into core and outside of your controllers, it sounds like you have a service layer (more or less). If this is the case, I think you could argue that you’re overloading your controller method. This is going to be an oversimplification from 1000 ft, but: If the mobile app and web client share the same business logic in the service layer and they require different flags why not have two separate routes and controller handlers?

  def index_web(conn, _params) do
    enabled = FeatureFlag.enabled?("my_web_flag", session)
    my_resource = MyAppCore.my_implementation(enabled, :undefined, get_session(conn))
    render(conn, "index.html", resource: my_resource)
  end

  def index_mobile(conn, _params) do
    enabled = FeatureFlag.enabled?("my_mobile_flag", session)
    my_resource = MyAppCore.my_implementation(:undefined, enabled, get_session(conn))
    render(conn, "index.html", resource: my_resource)
  end
  def my_implementation(true, _, session) do
    web_implementation
  end
  def my_implementation(_, true, session) do
    mobile_implementation
  end
  def my_implementation(_, _, session) do
    fallback_implemtation
  end

Ofcourse, if everything is live and running and the app is widely deployed, the choice might have already been made for you and you’ll need to get the flags in the controller based on whatever is in the session you’re using to differentiate mobile and web clients.

1 Like

Now, if you’re juggling 30 flags…this might be bad advice :slight_smile:

the choice might have already been made for you and you’ll need to get the flags in the controller

That is indeed the case.

Both interfaces for web and mobile are mixed together, idealy I would have loved to push the split even further by having a my_app_web and a my_app_mobile folder.

1 Like