arturo
arturo copied to clipboard
Can I deploy some features on a per-user basis and others on a per-account basis?
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
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)
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
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 returnsfalse
-
beta
--enabled?
checks a whitelist of recipients. For us, this is a list of subdomains -
rollout
--enabled?
first checks the recipient whitelist, then thedeployment_percentage
-
on
--enabled?
always returnstrue
You seem to be going after something similar, though you may not need all those features.
Is that what issue #16 is talking about?
Yes.
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 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
@plukevdh what have you done to solve this in your projects? I'm still not totally happy with anything we've got so far.
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.
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.)
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.)
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.
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