arturo icon indicating copy to clipboard operation
arturo copied to clipboard

Can I deploy some features on a per-user basis and others on a per-account basis?

Open jamesarosen opened this issue 14 years ago • 15 comments

This question from martinstreicher:

Can the feature_recipient be dynamic? I have an account and a network that might have different features -- which would be the recipient?

That's an interesting point use case that I hadn't considered. The problem is that #feature_recipient can't know which to return since it doesn't know which feature you're asking about. One option would be to change #if_feature_enabled(feature_name, &block) and #feature_enabled?(feature_name) to allow a second, optional argument that takes the place of the result of #feature_recipient. Specifically:

def if_feature_enabled(feature_name, recipient = nil, &block)
  recipient ||= self.feature_recipient
  ...
end

def feature_enabled?(feature_name, recipient = nil)
  recipient ||= self.feature_recipient
  ...
end

jamesarosen avatar Nov 03 '10 17:11 jamesarosen

Another idea would be to add an Arturo::FeatureRecipient mixin:

module Arturo
  module FeatureRecipient
    def feature_enabled?(feature_name)
      Arturo::Feature.to_feature(feature_name).enabled_for?(self)
    end
  end
end

Then you could mix that into Network and User and use them like so:

current_user.feature_enabled?(:feature_that_is_deployed_to_users)

current_user.network.feature_enabled?(:feature_that_is_deployed_to_networks)

jamesarosen avatar Nov 03 '10 18:11 jamesarosen

Possible solution is just to make #enabled_for? overridable. See

https://github.com/crunchy/arturo/blob/master/test/dummy_app/test/unit/features_override_test.rb

plukevdh avatar Jun 28 '12 05:06 plukevdh

At Zendesk, we've been using a modified version of Arturo, but I've been having trouble figuring out how to make it generally applicable. Our features have a state attribute in addition to the deployment_percentage. state can be any of the following:

  • off -- enabled? always returns false
  • beta -- enabled? checks a whitelist of recipients. For us, this is a list of subdomains
  • rollout -- enabled? first checks the recipient whitelist, then the deployment_percentage
  • on -- enabled? always returns true

You seem to be going after something similar, though you may not need all those features.

jamesarosen avatar Jun 28 '12 08:06 jamesarosen

Is that what issue #16 is talking about?

plukevdh avatar Jun 28 '12 15:06 plukevdh

Yes.

jamesarosen avatar Jun 28 '12 15:06 jamesarosen

I think the whitelist/blacklist concept handles a lot of these kinds of cases, or it could be used to do so. Maybe some sort of DSL for defining states -> what group is can access a feature per a boolean method. Something like

Arturo::RolloutScheme do |f|
  f.off = false
  f.beta = :in_beta_group?
  f.rollout = :passes_threshold?  
  f.on = true
end

Then then some sort eval checks the feature state, evals the given method (or just takes the bool) for the enabled state. this way it can be flexibly defined in an initializer or something.

plukevdh avatar Jun 28 '12 15:06 plukevdh

@plukevdh I like the DSL idea. What about making it a little more like FactoryGirl's DSL, which I like?

Arturo::Feature.phased_rollout do
  off     { false }
  beta    { |recipient| in_beta_group?(recipient) }
  rollout { |recipient| passes_threshold?(recipient) }
  on      { true }
end

jamesarosen avatar Mar 03 '13 23:03 jamesarosen

@plukevdh what have you done to solve this in your projects? I'm still not totally happy with anything we've got so far.

jamesarosen avatar May 01 '13 23:05 jamesarosen

Dude, you gotta not respond to ALL THE THINGS on one day. Spread the love around :)

Are we talking about dsls? I've got some good ones, but let me find a simple example somewhere. I'll get back on this. Shortly.

plukevdh avatar May 02 '13 01:05 plukevdh

I finished my sprint early, so I'm using the time to clean out old open source issues. It's a great feeling :)

Can you use the new global whitelists to solve this problem? Something like

Arturo.Feature.whitelist do |feature, _|
  feature.enabled_for?(0)
end

(And forget the phase DSL, at least for now. I'm happy to talk about it later, but I don't want to cloud the problem you're having here.)

jamesarosen avatar May 02 '13 01:05 jamesarosen

Yeah maybe. I still like the idea of the DSL. Your factorygirl-like example is cool too.

https://gist.github.com/plukevdh/5499688 is a DSL I wrote for setting abilities on a user for state machine control. Pretty simple and I think something similar could be done for this.

plukevdh avatar May 02 '13 01:05 plukevdh

Has there been any movement on this issue? This engine might be something that I want to use.

We have a situation where we may want multiple rules for a feature where they can be per company and per multiple groups and per operating area and per platform (like ios, web, etc.)

psulightning avatar Aug 19 '14 19:08 psulightning

No movement. I think the whitelist feature will suffice for most use-cases. If anyone comes up with a particularly elegant API / design, I'm all for considering an enhancement.

jamesarosen avatar Aug 19 '14 21:08 jamesarosen

Sure whitelisting would work if I wanted to hardcode (at least that's my interpretation from the readme). But, our configuration could be changing on the fly, so modifying the initializer every time is not feasible. Please let me know if my interpretation is mistaken.

psulightning avatar Aug 20 '14 11:08 psulightning

Let's assume that you enhance the features table and Feature model to understand whether it's an Account-based or User-based feature.

Let's further assume that you declare your (default) feature_recipient to be the current user, and the user has a reference to the account.

Then to get account-based rollout for those features that need it, you could do

Arturo::Feature.whitelist do |feature, user|
  if feature.is_account_feature?
    feature.enabled_for?(user.account)
  end
end

jamesarosen avatar Aug 20 '14 21:08 jamesarosen