Skip to content

Commit 7e79308

Browse files
JAMES NEIMAN CONSULTINGJAMES NEIMAN CONSULTING
authored andcommitted
Edits
1 parent cd93f02 commit 7e79308

File tree

1 file changed

+90
-74
lines changed
  • packages/optimizely-sdk/lib/core/decision_service

1 file changed

+90
-74
lines changed

packages/optimizely-sdk/lib/core/decision_service/index.js

Lines changed: 90 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -31,22 +31,22 @@ var DECISION_SOURCES = enums.DECISION_SOURCES;
3131

3232

3333
/**
34-
* Optimizely's decision service that determines which variation of an experiment the user will be allocated to.
34+
* A decision service that determines which variation of an experiment to which to allocate a user.
3535
*
36-
* The decision service contains all logic around how a user decision is made. This includes all of the following (in order):
37-
* 1. Checking experiment status
38-
* 2. Checking forced bucketing
39-
* 3. Checking whitelisting
40-
* 4. Checking user profile service for past bucketing decisions (sticky bucketing)
41-
* 5. Checking audience targeting
42-
* 6. Using Murmurhash3 to bucket the user.
36+
* The decision service contains all logic determining how a user decision is made. The following tasks are performed in order:
37+
* 1. Check the experiment status.
38+
* 2. Check for forced bucketing.
39+
* 3. Check for whitelisting.
40+
* 4. Check the user profile service for past bucketing decisions (sticky bucketing).
41+
* 5. Check for audience targeting.
42+
* 6. Bucket the user.
4343
*
4444
* @constructor
45-
* @param {Object} options
46-
* @param {Object} options.configObj The parsed project configuration object that contains all the experiment configurations.
47-
* @param {Object} options.userProfileService An instance of the user profile service for sticky bucketing.
48-
* @param {Object} options.logger An instance of a logger to log messages with.
49-
* @returns {Object}
45+
* @param {object} options The parsed project configuration object.
46+
* @param {object} options.configObj The parsed project configuration object that contains all of the experiment configurations.
47+
* @param {object} options.userProfileService An instance of the user profile service for sticky bucketing.
48+
* @param {object} options.logger An instance of a logger used to log messages.
49+
* @returns {object}
5050
*/
5151
function DecisionService(options) {
5252
this.configObj = options.configObj;
@@ -55,11 +55,11 @@ function DecisionService(options) {
5555
}
5656

5757
/**
58-
* Gets variation where visitor will be bucketed.
59-
* @param {string} experimentKey
60-
* @param {string} userId
61-
* @param {Object} attributes
62-
* @return {string|null} the variation the user is bucketed into.
58+
* Returns a variation where the visitor will be bucketed.
59+
* @param {string} experimentKey The ID of the experiment for which to get the variation.
60+
* @param {string} userId The ID of the visitor.
61+
* @param {object} attributes A collection of key/value pairs of user attributes.
62+
* @return {string|null} The variation into which the user is bucketed.
6363
*/
6464
DecisionService.prototype.getVariation = function(experimentKey, userId, attributes) {
6565
// by default, the bucketing ID should be the user ID
@@ -106,9 +106,10 @@ DecisionService.prototype.getVariation = function(experimentKey, userId, attribu
106106
};
107107

108108
/**
109-
* Merges attributes from attributes[STICKY_BUCKETING_KEY] and userProfileService
110-
* @param {Object} attributes
111-
* @return {Object} finalized copy of experiment_bucket_map
109+
* Merges attributes from 'attributes[STICKY_BUCKETING_KEY]' and 'userProfileService'.
110+
* @param {string} userId The ID of the user.
111+
* @param {object} attributes An optional key/value pair collection containing user attributes.
112+
* @return {object} A finalized copy of 'experiment_bucket_map' from the user's profile.
112113
*/
113114
DecisionService.prototype.__resolveExperimentBucketMap = function(userId, attributes) {
114115
attributes = attributes || {}
@@ -119,10 +120,10 @@ DecisionService.prototype.__resolveExperimentBucketMap = function(userId, attrib
119120

120121

121122
/**
122-
* Checks whether the experiment is running or launched
123-
* @param {string} experimentKey Key of experiment being validated
124-
* @param {string} userId ID of user
125-
* @return {boolean} True if experiment is running
123+
* Checks whether the experiment is running or launched.
124+
* @param {string} experimentKey The ID of the of experiment being validated.
125+
* @param {string} userId The ID of the user.
126+
* @return {boolean} `true` if the experiment is running, `false` if the experiment is not running.
126127
*/
127128
DecisionService.prototype.__checkIfExperimentIsActive = function(experimentKey, userId) {
128129
if (!projectConfig.isActive(this.configObj, experimentKey)) {
@@ -135,10 +136,10 @@ DecisionService.prototype.__checkIfExperimentIsActive = function(experimentKey,
135136
};
136137

137138
/**
138-
* Checks if user is whitelisted into any variation and return that variation if so
139-
* @param {Object} experiment
140-
* @param {string} userId
141-
* @return {string|null} Forced variation if it exists for user ID, otherwise null
139+
* Checks if a user is whitelisted into any variation, and returns that variation.
140+
* @param {Object} experiment The experiment to check for any forced variations.
141+
* @param {string} userId The ID of the user for whom to get the variation.
142+
* @return {string|null} The forced variation, if it exists, for the specified user ID; `null` otherwise.
142143
*/
143144
DecisionService.prototype.__getWhitelistedVariation = function(experiment, userId) {
144145
if (!fns.isEmpty(experiment.forcedVariations) && experiment.forcedVariations.hasOwnProperty(userId)) {
@@ -158,11 +159,11 @@ DecisionService.prototype.__getWhitelistedVariation = function(experiment, userI
158159
};
159160

160161
/**
161-
* Checks whether the user is included in experiment audience
162-
* @param {string} experimentKey Key of experiment being validated
163-
* @param {string} userId ID of user
164-
* @param {Object} attributes Optional parameter for user's attributes
165-
* @return {boolean} True if user meets audience conditions
162+
* Checks if a user is included in an experiment's audience.
163+
* @param {string} experimentKey The ID of the experiment being validated.
164+
* @param {string} userId The ID of the user to check.
165+
* @param {Object} attributes An optional key/value pair collection containing user attributes.
166+
* @return {boolean} `true` if the user meets audience conditions; `false` otherwise.
166167
*/
167168
DecisionService.prototype.__checkIfUserIsInAudience = function(experimentKey, userId, attributes) {
168169
var experimentAudienceConditions = projectConfig.getExperimentAudienceConditions(this.configObj, experimentKey);
@@ -177,11 +178,11 @@ DecisionService.prototype.__checkIfUserIsInAudience = function(experimentKey, us
177178
};
178179

179180
/**
180-
* Given an experiment key and user ID, returns params used in bucketer call
181-
* @param experimentKey Experiment key used for bucketer
182-
* @param bucketingId ID to bucket user into
183-
* @param userId ID of user to be bucketed
184-
* @return {Object}
181+
* Retrieves the parameters used in the bucketer call for a given experiment key and user ID.
182+
* @param {string} experimentKey The ID of the experiment used for the bucketer.
183+
* @param {string} bucketingId The ID into which to bucket the user.
184+
* @param {string} userId The ID of the user to be bucketed.
185+
* @return {Object} An object containing the bucketer parameters.
185186
*/
186187
DecisionService.prototype.__buildBucketerParams = function(experimentKey, bucketingId, userId) {
187188
var bucketerParams = {};
@@ -198,11 +199,11 @@ DecisionService.prototype.__buildBucketerParams = function(experimentKey, bucket
198199
};
199200

200201
/**
201-
* Pull the stored variation out of the experimentBucketMap for an experiment/userId
202-
* @param {Object} experiment
203-
* @param {String} userId
204-
* @param {Object} experimentBucketMap mapping experiment => { variation_id: <variationId> }
205-
* @return {Object} the stored variation or null if the user profile does not have one for the given experiment
202+
* Retrieves the stored variation for the specified experiment and user.
203+
* @param {Object} experiment The ID of the experiment from which to get the variation.
204+
* @param {String} userId The ID of the user for whom to get the variation,
205+
* @param {Object} experimentBucketMap A mapping between an experiment ID and variation ID.
206+
* @return {Object} The stored variation, or `null` if the user profile does not have a variation for the experiment.
206207
*/
207208
DecisionService.prototype.__getStoredVariation = function(experiment, userId, experimentBucketMap) {
208209
if (experimentBucketMap.hasOwnProperty(experiment.id)) {
@@ -219,9 +220,9 @@ DecisionService.prototype.__getStoredVariation = function(experiment, userId, ex
219220
};
220221

221222
/**
222-
* Get the user profile with the given user ID
223-
* @param {string} userId
224-
* @return {Object|undefined} the stored user profile or undefined if one isn't found
223+
* Retrieves the user profile for a specific user.
224+
* @param {string} userId The ID of the user.
225+
* @return {Object|undefined} The stored user profile, or 'undefined' if one isn't found.
225226
*/
226227
DecisionService.prototype.__getUserProfile = function(userId) {
227228
var userProfile = {
@@ -241,11 +242,11 @@ DecisionService.prototype.__getUserProfile = function(userId) {
241242
};
242243

243244
/**
244-
* Saves the bucketing decision to the user profile
245-
* @param {Object} userProfile
246-
* @param {Object} experiment
247-
* @param {Object} variation
248-
* @param {Object} experimentBucketMap
245+
* Saves the bucketing decision to the user profile.
246+
* @param {Object} experiment The experiment for which to save the bucketing decision.
247+
* @param {Object} variation The variation for which to save the bucketing decision.
248+
* @param {String} userId The ID of the user.
249+
* @param {Object} experimentBucketMap An object that maps an experiment ID to a variation ID.
249250
*/
250251
DecisionService.prototype.__saveUserProfile = function(experiment, variation, userId, experimentBucketMap) {
251252
if (!this.userProfileService) {
@@ -270,18 +271,16 @@ DecisionService.prototype.__saveUserProfile = function(experiment, variation, us
270271
};
271272

272273
/**
273-
* Given a feature, user ID, and attributes, returns an object representing a
274-
* decision. If the user was bucketed into a variation for the given feature
275-
* and attributes, the returned decision object will have variation and
276-
* experiment properties (both objects), as well as a decisionSource property.
277-
* decisionSource indicates whether the decision was due to a rollout or an
278-
* experiment.
279-
* @param {Object} feature A feature flag object from project configuration
280-
* @param {String} userId A string identifying the user, for bucketing
281-
* @param {Object} attributes Optional user attributes
282-
* @return {Object} An object with experiment, variation, and decisionSource
283-
* properties. If the user was not bucketed into a variation, the variation
284-
* property is null.
274+
* Retrieves an object containing a decision for a specific feature, user ID, and attributes.
275+
* If the user was bucketed into a variation for the specified feature
276+
* and attributes, the decision object returned will have both 'variation' and
277+
* 'experiment' properties, as well as a 'decisionSource' property.
278+
* 'decisionSource' indicates whether the decision was due to a rollout for an experiment.
279+
* @param {Object} feature The feature flag object from a project configuration.
280+
* @param {String} userId The ID of the user.
281+
* @param {Object} attributes An optional key/value pair collection containing user attributes.
282+
* @return {Object} An object containing 'experiment', 'variation', and 'decisionSource' properties.
283+
* If the user was not bucketed into a variation, the 'variation' property is null.
285284
*/
286285
DecisionService.prototype.getVariationForFeature = function(feature, userId, attributes) {
287286
var experimentDecision = this._getVariationForFeatureExperiment(feature, userId, attributes);
@@ -307,6 +306,14 @@ DecisionService.prototype.getVariationForFeature = function(feature, userId, att
307306
};
308307
};
309308

309+
/**
310+
* Retrieves an object containing a variation for a specific experiment.
311+
* @param {Object} feature The feature flag object from a project configuration.
312+
* @param {String} userId The ID of the user for the variation.
313+
* @param {Object} attributes An optional key/value pair collection containing user attributes.
314+
* @return {Object} An object containing 'experiment', 'variation', and 'decisionSource' properties.
315+
* If the user was not bucketed into a variation, the variation property is null.
316+
*/
310317
DecisionService.prototype._getVariationForFeatureExperiment = function(feature, userId, attributes) {
311318
var experiment = null;
312319
var variationKey = null;
@@ -341,6 +348,7 @@ DecisionService.prototype._getVariationForFeatureExperiment = function(feature,
341348
};
342349
};
343350

351+
344352
DecisionService.prototype._getExperimentInGroup = function(group, userId) {
345353
var experimentId = bucketer.bucketUserIntoExperiment(group, userId, userId, this.logger);
346354
if (experimentId !== null) {
@@ -355,6 +363,14 @@ DecisionService.prototype._getExperimentInGroup = function(group, userId) {
355363
return null;
356364
};
357365

366+
/**
367+
* Retrieves a variation for a specific feature rollout.
368+
* @param {Object} feature The feature flag object from a project configuration.
369+
* @param {String} userId The ID of the user for the variation.
370+
* @param {Object} attributes An optional key/value pair collection containing user attributes.
371+
* @return {Object} An object containing 'experiment', 'variation', and 'decisionSource' properties.
372+
* If the user was not bucketed into a variation, the variation property is null. If there are no experiments in the rollout, the experiment property is null.
373+
*/
358374
DecisionService.prototype._getVariationForRollout = function(feature, userId, attributes) {
359375
if (!feature.rolloutId) {
360376
this.logger.log(LOG_LEVEL.DEBUG, sprintf(LOG_MESSAGES.NO_ROLLOUT_EXISTS, MODULE_NAME, feature.key));
@@ -442,10 +458,10 @@ DecisionService.prototype._getVariationForRollout = function(feature, userId, at
442458
};
443459

444460
/**
445-
* Get bucketing Id from user attributes.
446-
* @param {String} userId
447-
* @param {Object} attributes
448-
* @returns {String} Bucketing Id if it is a string type in attributes, user Id otherwise.
461+
* Retrieves a bucketing ID for a specific user ID and user attributes.
462+
* @param {String} userId The ID of the user for the variation.
463+
* @param {Object} attributes An optional key/value pair collection containing user attributes.
464+
* @returns {String} The bucketing ID if it available in the attributes; otherwise the user ID is returned.
449465
*/
450466
DecisionService.prototype._getBucketingId = function(userId, attributes) {
451467
var bucketingId = userId;
@@ -465,12 +481,12 @@ DecisionService.prototype._getBucketingId = function(userId, attributes) {
465481

466482
module.exports = {
467483
/**
468-
* Creates an instance of the DecisionService.
469-
* @param {Object} options Configuration options
470-
* @param {Object} options.configObj
471-
* @param {Object} options.userProfileService
472-
* @param {Object} options.logger
473-
* @return {Object} An instance of the DecisionService
484+
* Creates an instance of the decision service.
485+
* @param {Object} options Configuration options.
486+
* @param {Object} options.configObj The parsed project configuration object that contains all of the experiment configurations.
487+
* @param {Object} options.userProfileService An instance of the user profile service for sticky bucketing.
488+
* @param {Object} options.logger An instance of a logger used to log messages.
489+
* @return {Object} An instance of the decision service.
474490
*/
475491
createDecisionService: function(options) {
476492
return new DecisionService(options);

0 commit comments

Comments
 (0)