-
Notifications
You must be signed in to change notification settings - Fork 19
feat(getFeatureVariableString): Add getFeatureVariableString API #71
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
Conversation
optimizely/client/client.go
Outdated
|
|
||
| var typeName = "" | ||
| var valueParsed interface{} | ||
| switch valueType.(type) { |
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.
Instead of passing in a variable for which we then get the type of, we can just pass in a string with the name of the type. This is less expensive to do.
optimizely/client/client.go
Outdated
| func (o *OptimizelyClient) GetFeatureVariableString(featureKey string, variableKey string, userContext entities.UserContext) (value string, err error) { | ||
| val, err := o.getFeatureVariable("", featureKey, variableKey, userContext) | ||
| if err == nil { | ||
| switch val.(type) { |
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.
Here we can
if returnValue, ok := val.(string); ok {
value = returnValue
}
Then at the end you return the named variables value, err
optimizely/client/client.go
Outdated
| } | ||
|
|
||
| func (o *OptimizelyClient) getFeatureVariable(valueType interface{}, featureKey string, variableKey string, userContext entities.UserContext) (value interface{}, err error) { | ||
| if !o.isValid { |
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 feel this check, along with the project config check below can likely be collapsed into a isValid method that takes in the method name so it can print it out if not valid
optimizely/interface.go
Outdated
| GetEventByKey(string) (entities.Event, error) | ||
| GetExperimentByKey(string) (entities.Experiment, error) | ||
| GetFeatureByKey(string) (entities.Feature, error) | ||
| GetFeatureFlagByKey(string) (datafileEntities.FeatureFlag, error) |
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.
This is wrong. Feature flags an d features are the same thing. You are bringing in the data file raw feature flags in here, which is not what we want.
| } | ||
|
|
||
| // GetVariable returns variable for key from feature flag | ||
| func (f *FeatureFlag) GetVariable(key string) (Variable, error) { |
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.
Instead of adding this functionality to the model, let's add this method to the project config itself to get a variable with key from the feature
| experimentKeyToIDMap map[string]string | ||
| experimentMap map[string]entities.Experiment | ||
| featureMap map[string]entities.Feature | ||
| featureFlagMap map[string]datafileEntities.FeatureFlag |
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.
See comment at bottom. This is incorrect. We should be using the entities.* which are public facing. The datafileEntities are internal models that we don't expose and are only needed so we can parse into entities.* models
mikeproeng37
left a comment
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.
Mostly good. I have a few more suggestions
| } | ||
|
|
||
| for _, variable := range rawVariation.Variables { | ||
| variation.Variables = append(variation.Variables, entities.VariationVariable{ID: variable.ID, Value: variable.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.
I think we can benefit from making Feature.Variables a map of string to variable for easier access. It also helps that we can easily iterate over maps in Go.
optimizely/client/client_test.go
Outdated
| DefaultValue: "default", | ||
| ID: "1", | ||
| Key: "test_feature_flag_key", | ||
| Type: "string"} |
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 move the } to a new line
optimizely/client/client_test.go
Outdated
| DefaultValue: "default", | ||
| ID: "1", | ||
| Key: "test_feature_flag_key", | ||
| Type: "boolean"} |
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.
Move the } to a new line
optimizely/client/client_test.go
Outdated
| DefaultValue: "defaultString", | ||
| ID: "1", | ||
| Key: "test_feature_flag_key", | ||
| Type: "string"} |
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.
ditto above
| Key string `json:"key"` | ||
| FeatureEnabled bool `json:"featureEnabled"` | ||
| ID string `json:"id"` | ||
| Variables []VariationVariable `json:"variables"` |
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 can use a map here to make look-ups easier.
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 have updated the public facing dataModel of Variation with a map for Variables.
https://github.com/optimizely/go-sdk/pull/71/files#diff-f55225b09df17f6c9183261f39659ee1R22
| assert.Equal(t, 1, processor.EventsCount()) | ||
|
|
||
| time.Sleep(200 * time.Millisecond) | ||
| time.Sleep(2000 * time.Millisecond) |
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 this because the test is flaky?
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.
yes, i had instances where it failed, increasing the timeout made it more stable.
optimizely/client/client.go
Outdated
| return value, err | ||
| } | ||
|
|
||
| func (o *OptimizelyClient) getFeatureVariable(valueType string, featureKey string, variableKey string, userContext entities.UserContext) (value interface{}, err error) { |
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 conceptually it will be better if that function returns the string instead of interface and GetFeatureVariableString does the checking. That way we eliminate valueType parameter.
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.
actually GetFeatureVariableString will not have to do any checking - just pass-through, but GetFeatureVariableBool, GetFeatureVariableFloat, etc will do some checking
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.
That is a great point. I think we should do it that way even if it ends up duplicating some of the code at the bottom since strong typing does give us other kinds of guarantees @yasirfolio3
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.
@pawels-optimizely we need valueType parameter for this condition
https://github.com/optimizely/go-sdk/pull/71/files#diff-b852811f33e54bd7b6e89917e41eefadR203
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 yes we can move the checking part to each individual api such as GetFeatureVariableString, but we would still need valueType argument to check if variable.Type is the required valueType, any thoughts?
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.
you are calling it as getFeatureVariable("string", featureKey, variableKey, userContext), that means variable "2" would be treated as a string in GetFeatureVariableString
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.
also if you need the type, you can return a string and the type and check that in GetFeatureVariableString. try to avoid returning interface{} unless you really have to.
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.
also if you need the type, you can return a string and the type and check that in GetFeatureVariableString
il go ahead with this idea!
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, sorry to be a pain - I am not 100% on this code yet, but it's kind of awkward flow when I read the code: 1. getting a string, 2. converting to interface, 3. returning the interface, 4. converting interface to string again - this is your overall flow. Just trying to avoid that.
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.
no worries, can you review it now!
| } | ||
|
|
||
| // GetFeatureVariableString returns string feature variable value | ||
| func (o *OptimizelyClient) GetFeatureVariableString(featureKey string, variableKey string, userContext entities.UserContext) (value string, err error) { |
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.
nice !, much cleaner now, no hardcoded parameter, more readable, no unneeded interface. small change but cleaned a lot of things and eliminated confusion. lgtm
mikeproeng37
left a comment
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 one more comment on it!
optimizely/client/client.go
Outdated
| } | ||
| } | ||
|
|
||
| if featureValue == "" { |
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 this still needed? Empty strings should be OK. I think we should revert the above flow where if err != nil then we return this error message
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.
done! i'l do that for other getFeatureVariable API's, getFeatureVariableString doesn't require type-casting so i don't think we need it.
mikeproeng37
left a comment
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
|
@yasirfolio3 can you please resolve merge conflicts? |
yep, done! |
mikeproeng37
left a comment
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
Summary
GetFeatureVariableStringas a function inclient.goGetVariableByKey()function indatafileprojectconfig/config.goTests
client_test.goIssues
OASIS-5006