Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

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

Open
jamesarosen opened this Issue Nov 3, 2010 · 15 comments

Comments

Projects
None yet
3 participants
Contributor

jamesarosen commented Nov 3, 2010

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
Contributor

jamesarosen commented Nov 3, 2010

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)
Collaborator

plukevdh commented Jun 28, 2012

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

Contributor

jamesarosen commented Jun 28, 2012

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.

Collaborator

plukevdh commented Jun 28, 2012

Is that what issue #16 is talking about?

Contributor

jamesarosen commented Jun 28, 2012

Yes.

Collaborator

plukevdh commented Jun 28, 2012

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.

Contributor

jamesarosen commented Mar 3, 2013

@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
Contributor

jamesarosen commented May 1, 2013

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

Collaborator

plukevdh commented May 2, 2013

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.

Contributor

jamesarosen commented May 2, 2013

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.)

Collaborator

plukevdh commented May 2, 2013

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.

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.)

Contributor

jamesarosen commented Aug 19, 2014

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.

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.

Contributor

jamesarosen commented Aug 20, 2014

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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment