Skip to content

feat(OptimizelyConfig): Add new fields to OptimizelyConfig #698

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

Merged
merged 12 commits into from
Aug 13, 2021

Conversation

yasirfolio3
Copy link
Contributor

@yasirfolio3 yasirfolio3 commented Aug 11, 2021

Summary

The following new public properties are added to OptimizelyConfig:

  • sdkKey
  • environmentKey
  • attributes
  • audiences
  • events
  • experimentRules and deliveryRules to OptimizelyFeature
  • audiences to OptimizelyExperiment

Test plan

All FSC tests OPTIMIZELY_CONFIG_V2 tests should pass.
FSC OptimizelyConfig link

@coveralls
Copy link

coveralls commented Aug 11, 2021

Coverage Status

Coverage increased (+0.02%) to 97.002% when pulling 47706af on yasir/config-v2 into a37cfb2 on master.


constructor(configObj: ProjectConfig, datafile: string) {
this.experimentsMap = OptimizelyConfig.getExperimentsMap(configObj);
this.featuresMap = OptimizelyConfig.getFeaturesMap(configObj, this.experimentsMap);
this.sdkKey = configObj.sdkKey ? configObj.sdkKey : '';
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use configObj.sdkKey ?? ''; if you want.

let cond = '';
conditions.forEach((item) => {
let subAudience = '';
// Checks if item is list of conditions means if it is sub audience
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// Checks if item is list of conditions means it is sub audience

Comment on lines 18 to 24
Audience,
Experiment,
FeatureVariable,
OptimizelyExperimentsMap,
OptimizelyFeaturesMap,
OptimizelyVariablesMap,
FeatureVariable,
OptimizelyAttribute,
OptimizelyAudience,
OptimizelyEvent,
OptimizelyExperiment,
OptimizelyVariable,
OptimizelyVariation,
Rollout,
VariationVariable,
Variation,
Rollout,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: arrange these in alphabetical order

private datafile: string;
private static audienceConditionalOperators: string[] = ['and', 'or', 'not'];
Copy link
Contributor

@zashraf1985 zashraf1985 Aug 11, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can probably be moved to ENUMS?


constructor(configObj: ProjectConfig, datafile: string) {
this.experimentsMap = OptimizelyConfig.getExperimentsMap(configObj);
this.featuresMap = OptimizelyConfig.getFeaturesMap(configObj, this.experimentsMap);
this.sdkKey = configObj.sdkKey ? configObj.sdkKey : '';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
this.sdkKey = configObj.sdkKey ? configObj.sdkKey : '';
this.sdkKey = configObj.sdkKey || '';

this.experimentsMap = OptimizelyConfig.getExperimentsMap(configObj);
this.featuresMap = OptimizelyConfig.getFeaturesMap(configObj, this.experimentsMap);
this.sdkKey = configObj.sdkKey ? configObj.sdkKey : '';
this.environmentKey = configObj.environmentKey ? configObj.environmentKey : '';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
this.environmentKey = configObj.environmentKey ? configObj.environmentKey : '';
this.environmentKey = configObj.environmentKey || '';

* @returns {OptimizelyAudience[]} Array of unique audiences
*/
static getAudiences(configObj: ProjectConfig): OptimizelyAudience[] {
const finalAudiences: OptimizelyAudience[] = [];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why call it finalAudiences? can you simply call it audiences

Comment on lines 140 to 175
if (item instanceof Array) {
subAudience = OptimizelyConfig.GetSerializedAudiences(item, audiencesById);
subAudience = `(${subAudience})`;
} else if (OptimizelyConfig.audienceConditionalOperators.includes(item)) {
cond = item.toUpperCase();
} else {
// Checks if item is audience id
const audienceName = audiencesById[item] ? audiencesById[item].name : item;
// if audience condition is "NOT" then add "NOT" at start. Otherwise check if there is already audience id in serializedAudience then append condition between serializedAudience and item
if (serializedAudience || cond === 'NOT') {
cond = cond === '' ? 'OR' : cond;
if (serializedAudience === '') {
serializedAudience = `${cond} "${audiencesById[item].name}"`;
} else {
serializedAudience = serializedAudience.concat(` ${cond} "${audienceName}"`);
}
} else {
serializedAudience = `"${audienceName}"`;
}
}
// Checks if sub audience is empty or not
if (subAudience !== '') {
if (serializedAudience !== '' || cond === 'NOT') {
cond = cond === '' ? 'OR' : cond;
if (serializedAudience === '') {
serializedAudience = `${cond} ${subAudience}`;
} else {
serializedAudience = serializedAudience.concat(` ${cond} ${subAudience}`);
}
} else {
serializedAudience = serializedAudience.concat(subAudience);
}
}
});
}
return serializedAudience;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NOT reviewing this code. will leave it to @msohailhussain and @jaeopt as they have more context about this particular peice


const variableIdMap = OptimizelyConfig.getVariableIdMap(configObj);

experiments.forEach((experiment) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you could use map here and assigned the result directly to deliveryRules?

},
{},
)
experiments.forEach((experiment) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could do reduce here probably?

datafileCopy.environmentKey = datafile.environmentKey;
datafileCopy.sdkKey = datafile.sdkKey;
}
datafileCopy.environmentKey = datafile.environmentKey ? datafile.environmentKey : '';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
datafileCopy.environmentKey = datafile.environmentKey ? datafile.environmentKey : '';
datafileCopy.environmentKey = datafile.environmentKey || '';

datafileCopy.sdkKey = datafile.sdkKey;
}
datafileCopy.environmentKey = datafile.environmentKey ? datafile.environmentKey : '';
datafileCopy.sdkKey = datafile.sdkKey ? datafile.sdkKey : '';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
datafileCopy.sdkKey = datafile.sdkKey ? datafile.sdkKey : '';
datafileCopy.sdkKey = datafile.sdkKey || '';

@yavorona yavorona self-requested a review August 11, 2021 21:57
export type OptimizelyAudience = {
id: string;
name: string;
conditions: unknown[] | string;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It appears that we expect conditions type here to just be string since we JSON.stringify the typedAudience/oldAudience conditions

* @param {string} featureId
* @returns {[key: string]: Variation} Variations mapped by key
*/
static GetVariationsMap(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this method is also capitalized?

* @param {[id: string]: Audience} audiencesById
* @returns {string} Serialized audiences condition string
*/
static GetSerializedAudiences(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we capitalizing this method?

@@ -248,6 +249,7 @@ export interface OptimizelyOptions {
export interface OptimizelyExperiment {
id: string;
key: string;
audiences: unknown[] | string;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should just be string

configObj: ProjectConfig,
featureVariableIdMap: FeatureVariablesMap,
featureId: string,
experiments: Experiment[] | undefined
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should not be expected undefined as every rollout object should contain experiments. @msohailhussain please correct if I am wrong.

experiments: Experiment[] | undefined
): OptimizelyExperiment[] {
const deliveryRules: OptimizelyExperiment[] = [];
if (!experiments) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If above is true, this if statement is unnecessary.

isFeatureEnabled: boolean | undefined
): OptimizelyVariablesMap {
let variablesMap: OptimizelyVariablesMap = {};
if (!featureId) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This statement seems unnecessary as we should expect a valid featureId, right?

Copy link
Contributor

@msohailhussain msohailhussain left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please address

*/
static getAudiences(configObj: ProjectConfig): OptimizelyAudience[] {
const finalAudiences: OptimizelyAudience[] = [];
const typedAudienceIds: { [id: string]: boolean } = {};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i agree. there is one more existing code that's using the same kv map, we should use .includes and only use Ids arrays.

@@ -69,150 +332,122 @@ export class OptimizelyConfig {
static getRolloutExperimentIds(rollouts: Rollout[]): { [key: string]: boolean } {
return (rollouts || []).reduce((experimentIds: { [key: string]: boolean }, rollout) => {
rollout.experiments.forEach((e) => {
(experimentIds)[e.id] = true;
experimentIds[e.id] = true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comment, use .includes more cleaner.

Copy link
Contributor

@yavorona yavorona left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good except for couple of minor comments and failing browser stack tests.

featureId: string
): { [key: string]: Variation } {
let variationsMap: { [key: string]: OptimizelyVariation } = {};
variationsMap = variations.reduce((OptlyVariationsMap: { [key: string]: OptimizelyVariation }, variation) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

optlyVariationsMap instead of OptlyVariationsMap

isFeatureEnabled: boolean | undefined
): OptimizelyVariablesMap {
const variablesMap = (featureIdVariableMap[featureId] || []).reduce(
(OptlyVariablesMap: OptimizelyVariablesMap, featureVariable) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

optlyVariablesMap instead of OptlyVariablesMap

Copy link
Contributor

@jaeopt jaeopt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks great!

  • One comment about using OptimizelyConfig types internally.
  • Also I do not see duplicate-key warning about experimentsMap in OptimizelyConfig and deprecation warning about experimentsMap in OptimizelyFeature.

@@ -81,7 +83,7 @@ export interface ProjectConfig {
groupIdMap: { [id: string]: Group };
groups: Group[];
events: Event[];
attributes: Array<{ id: string }>;
attributes: OptimizelyAttribute[];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's not a good idea to use "OptimizelyAttribute" or other "OptimizelyXYZ" types in here.
Even if they look identical for now, we should separate them as public types only.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

makes sense, thanks.

@yasirfolio3
Copy link
Contributor Author

Overall looks great!

  • One comment about using OptimizelyConfig types internally.
  • Also I do not see duplicate-key warning about experimentsMap in OptimizelyConfig and deprecation warning about experimentsMap in OptimizelyFeature.

Had already added for OptimizelyFeature here: https://github.com/optimizely/javascript-sdk/pull/698/files#diff-2f8a7f1ccf360ce99abd03c811c59f9488fa24db24f8578d808e813e75192acdR330

Also added for OptimizelyConfig Interface here but forgot about the class which i have added now. Comment on the interface can be seen here: https://github.com/optimizely/javascript-sdk/pull/698/files#diff-2f8a7f1ccf360ce99abd03c811c59f9488fa24db24f8578d808e813e75192acdR347

@yasirfolio3 yasirfolio3 requested a review from jaeopt August 13, 2021 18:54
Copy link
Contributor

@jaeopt jaeopt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM
nit - add a period (.) at the end of "This experimentsMap is for experiments of legacy projects only" in multiple places.

@msohailhussain msohailhussain merged commit d32c80f into master Aug 13, 2021
@msohailhussain msohailhussain deleted the yasir/config-v2 branch August 13, 2021 22:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants