-
Notifications
You must be signed in to change notification settings - Fork 83
feat (audience match types): Update audience evaluator and project config for new audience match types #173
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat (audience match types): Update audience evaluator and project config for new audience match types #173
Conversation
projectConfig.typedAudiences first, then fall back to projectConfig.audiences
attributes are passed in
…hods accepting user attributes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't yet looked at the test cases. I'll try to get to them soon. In the meantime, here is some feedback.
@@ -30,9 +31,8 @@ module.exports = { | |||
return true; | |||
} | |||
|
|||
// if no user attributes specified, return false | |||
if (!userAttributes) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be fine because we do validate that the userAttributes
is either an object or null
and thus falsy values don't make it here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I don't think it needs to be the job of this module to handle other types of falsy values. Gracefully overwriting all falsy values seems reasonable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mikeng13 @nchilada I'm not sure if you're agreeing with my change, or requesting that this be left the way it was.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we're both agreeing! At least I am. Sorry for the confusion.
@@ -546,6 +598,73 @@ var configWithFeatures = { | |||
'id': '594017', | |||
'name': 'test_audience', | |||
'conditions': '["and", ["or", ["or", {"type": "custom_attribute", "name": "test_attribute", "value": "test_value"}]]]' | |||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a thought... but at some point maybe we can consolidate the test datafiles that we use across unit and compat tests
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree. The test datafiles have become large and unwieldy, and this PR is making it worse. Given @nchilada's other test-related comment also, I'm rethinking some of these tests.
@@ -20,8 +20,9 @@ module.exports = { | |||
* Determine if the given user attributes satisfy the given audience conditions | |||
* @param {Object[]} audiences Audiences to match the user attributes against | |||
* @param {Object[]} audiences.conditions Audience conditions to match the user attributes against | |||
* @param {Object} userAttributes Hash representing user attributes which will be used in determining if | |||
* the audience conditions are met | |||
* @param {Object} [userAttributes] Hash representing user attributes which will be used in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please also update the license header in this file and others you have touched that haven't had their license headers updated to this year.
fns.forEach(projectConfig.typedAudiences, function(audience) { | ||
audience.conditions = JSON.parse(audience.conditions); | ||
}); | ||
projectConfig.typedAudienceIdMap = fns.keyBy(projectConfig.typedAudiences, 'id'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any reason to maintain a separate map? Any conflicts in ID's would get overwritten with the typed audience, which is what we want.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1, a single map would be nice.
And maybe call it audiencesById
since it's storing audiences and not IDs? But maybe I'm just parsing it weirdly
var audiencesInExperiment = fns.filter(projectConfig.audiences, function(audience) { | ||
return audienceIds.indexOf(audience.id) !== -1; | ||
fns.forEach(audienceIds, function(audienceId) { | ||
var typedAudience = projectConfig.typedAudienceIdMap[audienceId]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Haha I dunno why we did the lookup the other way around in the first place. This is so much better :)
audiencesInExperiment.push(typedAudience); | ||
return; | ||
} | ||
var audience = projectConfig.audienceIdMap[audienceId]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we have just one consolidated map, we'd just have to look in one place.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if we need to test each match type with each API. We just need to make sure that each API does some audience targeting, so we could probably get away with ~2 test cases for each API, one where an experiment's audienceIds
collectively pass and one where they collectively fail.
That said, I'm not going to complain too much about thorough tests 😄 LGTM!
P.S. I would also err on the side of whatever's simplest for the moment (either in terms of the smallest change to the codebase or the smallest additional change to this PR): when we tackle audience combinations there'll be another layer of complexity that we'll suddenly have to care about.
…evel methods accepting user attributes" This reverts commit 7bd1c6a.
…iences to the new config.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
build |
Summary
This updates project config and the audience evaluator to finish the implementation of typed audience evaluation:
false
when no attributes were passed)createProjectConfig
, set up a by-id object for accessing audiences from bothaudiences
andtypedAudiences
. Also, updategetAudiencesForExperiment
to first look inprojectConfig.typedAudiences
, and only look inprojectConfig.audiences
as a fallback.Test Plan