-
Notifications
You must be signed in to change notification settings - Fork 28
Feature Flag & Rollouts - Decision Service Logic #69
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
Feature Flag & Rollouts - Decision Service Logic #69
Conversation
commit 75224a4 Author: Owais <oakbani@folio3.com> Date: Thu Oct 26 18:14:31 2017 +0500 :memo: Final changes commit 75fa44d Author: Owais <oakbani@folio3.com> Date: Thu Oct 26 16:29:35 2017 +0500 # Conflicts: # tests/ProjectConfigTest.php # tests/UtilsTests/ValidatorTest.php commit a443056 Author: Owais <oakbani@folio3.com> Date: Thu Oct 26 12:21:16 2017 +0500 Partial fixes commit e03926b Author: Owais <oakbani@folio3.com> Date: Tue Oct 24 17:07:39 2017 +0500 Squashed commit of the following: commit 24569b8 Author: Owais <oakbani@folio3.com> Date: Fri Oct 20 18:18:55 2017 +0500 :pen: Fixed Code Coverage commit a6fa1e6 Author: Owais <oakbani@folio3.com> Date: Tue Oct 24 16:46:44 2017 +0500 :pen2: All Unit tests completed commit 72173d0 Author: Owais <oakbani@folio3.com> Date: Mon Oct 23 20:36:21 2017 +0500 :pen: 90% Unit tests done commit 9051dda Author: Owais <oakbani@folio3.com> Date: Mon Oct 23 18:41:04 2017 +0500 :pen: Unit tests done for feature experiment commit 8a5722d Author: Owais <oakbani@folio3.com> Date: Mon Oct 23 13:13:53 2017 +0500 :pen: Implementation First pass done commit 92dd219 Author: Owais <oakbani@folio3.com> Date: Fri Oct 20 17:32:04 2017 +0500 :pen: Feature Flag bucketing to Experiment done :memo: Todo: Rollout Logic commit ad15a2c Author: Owais <oakbani@folio3.com> Date: Fri Oct 20 12:52:47 2017 +0500 :pen: indentation commit dc41bf9 Author: Owais <oakbani@folio3.com> Date: Thu Oct 19 17:36:46 2017 +0500 :pencil2: Added Logger to Validator :pencil2: Added method defs commit 547b7ad Author: Owais <oakbani@folio3.com> Date: Thu Oct 19 17:11:22 2017 +0500 Feature Flags models and parsing from new v4 file
|
Can one of the admins verify this patch? |
1 similar comment
|
@asaschachar Can you please check for reviewer. |
| use Optimizely\UserProfile\UserProfileUtils; | ||
| use Optimizely\Utils\Validator; | ||
| use Optimizely\Entity\FeatureFlag; | ||
| use Optimizely\Entity\Rollout; |
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.
nit. Alphabetize
| /** | ||
| * Gets the Bucketing Id for Bucketing | ||
| * @param string $userId | ||
| * @param array $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.
nit. Space above this line between params and return
| return $variation; | ||
| } | ||
|
|
||
| /** |
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.
nit. ID
| * @return array/null {"experiment" : Experiment, "variation": Variation } / null | ||
| */ | ||
| public function getVariationForFeature(FeatureFlag $featureFlag, $userId, $userAttributes){ | ||
| //Evaluate in this order: |
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.
nit. At any point in time user will only be part of 1 experiment. A more accurate statement will be Attempt to bucket user into experiment using feature flag
| */ | ||
| public function getVariationForFeature(FeatureFlag $featureFlag, $userId, $userAttributes){ | ||
| //Evaluate in this order: | ||
| //1. Attempt to bucket user into all experiments in the feature flag. |
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.
nit. ...rollout using the feature...
| * @param array $userAttributes | ||
| * @return string | ||
| */ | ||
| private function getBucketingId($userId, $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.
nit. By
| $this->_logger->log(Logger::INFO, | ||
| "User '{$userId}' is bucketed into a rollout for feature flag '{$featureFlag->getKey()}'." | ||
| ); | ||
|
|
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 would request you to model this more as how it is in the Python SDK to be explicit that an event needs to be sent or not. See here: https://github.com/optimizely/python-sdk/blob/master/optimizely/decision_service.py#L195
🖊️ Logic slightly changed based on Decision 🖊️ nits addressed
|
@aliabbasrizvi Decision Object added and logic modified. Let me know if there is something else |
# Conflicts: # src/Optimizely/Entity/Variation.php # src/Optimizely/ProjectConfig.php # src/Optimizely/Utils/Validator.php # tests/DecisionServiceTests/DecisionServiceTest.php # tests/ProjectConfigTest.php # tests/TestData.php
…ationForFeature # Conflicts: # src/Optimizely/Entity/Variation.php # src/Optimizely/ProjectConfig.php # src/Optimizely/Utils/Validator.php # tests/ProjectConfigTest.php # tests/TestData.php
|
@aliabbasrizvi Let me know if there is anything else |
aliabbasrizvi
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.
Multiple fixes needed for styling. Please use other files in the repo as an example for how styling should be done.
| class Decision | ||
| { | ||
| const DECISION_SOURCE_EXPERIMENT = 'experiment'; | ||
| const DECISION_SOURCE_ROLLOUT = 'rollout'; |
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.
Commenting from https://github.com/optimizely/php-sdk/pull/71/files but please adjust indentation in this file. It looks like there is 5 spaces here and 2 spaces else where whereas we should be at 4 spaces.
|
|
||
| /** | ||
| * Gets the Bucketing ID for Bucketing | ||
| * @param string $userId |
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.
nit. Please add more description for the 2 fields by looking else where
| * Gets the Bucketing ID for Bucketing | ||
| * @param string $userId | ||
| * @param array $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.
nit. Describe what is actually returned.
| * Get the variation the user is bucketed into for the given FeatureFlag | ||
| * @param FeatureFlag $featureFlag The feature flag the user wants to access | ||
| * @param string $userId user id | ||
| * @param array $userAttributes 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.
nit. Like above, these comments can be more descriptive.
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.
Mention when null is returned and when decision is
| // Check if the feature flag has rollout and the user is bucketed into one of it's rules | ||
| $decision = $this->getVariationForFeatureRollout($featureFlag, $userId, $userAttributes); | ||
| if($decision){ | ||
| $this->_logger->log(Logger::INFO, |
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 the comments in Python SDK are more appropriate. Something like: https://github.com/optimizely/python-sdk/blob/master/optimizely/decision_service.py#L190
Perhaps, be User '{$userId} meets conditions for a targeting rule of rollout for feature flag {$featureFlag->getKey()}
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.
The placement of log messages in python has been done differently. I have mainly followed Ruby and Java messages in this change.
'{$userId} meets conditions for a targeting rule of rollout for feature flag {$featureFlag->getKey()}
This message fits when the user meets the audience conditions for the rollout rule. That's not we intend to say here.
| return null; | ||
| } | ||
|
|
||
| /** |
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.
There is only 1 rollout, not one of the rollouts.
| if(sizeof($rolloutRules) == 0) | ||
| return null; | ||
|
|
||
| // Evaluate all rollout rules except for last one |
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.
Not particularly fond of the spacing here. Please add spaces around the operators
| sprintf("Attempting to bucket user '{$userId}' into rollout rule '%s'.", $experiment->getKey())); | ||
|
|
||
| // Evaluate if user satisfies the traffic allocation for this rollout rule | ||
| $variation = $this->_bucketer->bucket($this->_projectConfig, $experiment, $bucketing_id, $userId); |
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.
Similar comment as above
| return new Decision($experiment->getId(), $variation->getId(), DECISION::DECISION_SOURCE_ROLLOUT); | ||
| } else { | ||
| $this->_logger->log(Logger::DEBUG, | ||
| "User '{$userId}' was excluded due to traffic allocation. Checking 'Eveyrone Else' rule now."); |
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.
Align the b of break with "
| if($variation && $variation != new Variation()){ | ||
| return new Decision($experiment->getId(), $variation->getId(), DECISION::DECISION_SOURCE_ROLLOUT); | ||
| } else { | ||
| $this->_logger->log(Logger::DEBUG, |
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.
Too many spaces before was
|
@aliabbasrizvi Addressed styling issues 2abf1ad. |
aliabbasrizvi
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.
Please add unit tests. Are they added in PR 71?
| * | ||
| * @return string the bucketing ID assigned to user | ||
| */ | ||
| private function getBucketingId($userId, $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.
nit. Please place this method on line 86 i.e. above getVariation. We should try and put private functions together as well as functions being referenced above functions they are being referenced in.
| } | ||
|
|
||
| /** | ||
| * Gets the Bucketing ID for Bucketing |
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.
Gets the ID for bucketing
|
|
||
| return $decision; | ||
| } else { | ||
| $this->_logger->log( |
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.
nit. Just a note on styling. I hope this suggestion will help improve readability, but we can remove the else clause and all statements i.e. line 197 - 202 will be executed anyway. That way, I do not have to figure out when the else is triggered and just by looking at the function I know if the else is not met, it will end up returning null
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 will be similar to what you do in the next function i.e. getVariationForFeatureExperiment
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.
Right. Thanks for pointing it out.
| { | ||
| $feature_flag_key = $featureFlag->getKey(); | ||
| $experimentIds = $featureFlag->getExperimentIds(); | ||
| //Check if there are any experiment ids inside feature flag |
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.
nit. Inset empty line above this statement.
| */ | ||
| namespace Optimizely\DecisionService; | ||
|
|
||
| class Decision |
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 see the problem with Decision being a thing in UserProfile also. Please rename this to FeatureDecisionto make the distinction.
| $variationId = $variation->getId(); | ||
| if (is_null($decision)) { | ||
| $decision = new Decision($variationId); | ||
| $decision = new \Optimizely\UserProfile\Decision($variationId); |
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.
Lets avoid the name conflict and rename the new thing to FeatureDecision
| * @return Decision if a variation is returned for the user | ||
| * null if feature flag is not used in any experiments or no variation is returned for the user | ||
| */ | ||
| public function getVariationForFeatureExperiment(FeatureFlag $featureFlag, $userId, $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.
Unit tests missing for this
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.
| * @return Decision if getVariationForFeatureExperiment or getVariationForFeatureRollout returns a Decision | ||
| * null otherwise | ||
| */ | ||
| public function getVariationForFeature(FeatureFlag $featureFlag, $userId, $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.
Unit tests missing for this
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.
They are in place. Please see them here: https://github.com/msohailhussain/php-sdk/blob/2abf1adbf9e25e9cfdcbb90af02431b41a19d71a/tests/DecisionServiceTests/DecisionServiceTest.php#L736-#L824
…ision, repositioned getBucketingId
|
@aliabbasrizvi Please see the changes here. eb54a9d |
aliabbasrizvi
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.
Please address remaining styling comments before merging. Please be consistent in spacing in comments.
| { | ||
| // By default, the bucketing ID should be the user ID | ||
| $bucketingId = $userId; | ||
|
|
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.
nit. Line seems too long. Please break up into 2 lines.
| $feature_flag_key = $featureFlag->getKey(); | ||
| $experimentIds = $featureFlag->getExperimentIds(); | ||
|
|
||
| //Check if there are any experiment ids inside feature flag |
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.
nit. IDs
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, please be consistent in commenting style. Some places like here there is no space after //and then on line 229 there is space. The spacing is correct on line 229.
| return null; | ||
| } | ||
|
|
||
| // Evaluate each experiment id and return the first bucketed experiment variation |
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.
nit. ID
| } | ||
|
|
||
| /** | ||
| * Get the variation if the user is bucketed into rollout on this feature flag |
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.
nit. rollout for this feature flag.
src/Optimizely/Utils/Validator.php
Outdated
| foreach ($validator->getErrors() as $error) { | ||
| $logger->log(Logger::DEBUG, "[%s] %s\n", $error['property'], $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.
Seems unnecessary
|
@wangjoshuah @aliabbasrizvi if anything is not pending, can u plz merge this PR. |
|
build |
|
build |
|
build |
1 similar comment
|
build |
👂 Will also show changes of data models and file parsing until first PR is merged
🖊 getVariationForFeature and Unit Tests