Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Feature Flags Are Flawed: Let's Make Them Better

404 views

Published on

An introduction to Feature Flags, canary deployments and finally, Swivel: A PHP library that will manage cohorts and features automatically for the developer.

Published in: Software
  • Be the first to comment

  • Be the first to like this

Feature Flags Are Flawed: Let's Make Them Better

  1. 1. FEATURE FLAGS ARE FLAWED LET'S MAKE THEM BETTER Created by Stephen Young / @young_steveo
  2. 2. FEATURE FLAG? I've seen a lot of names for this concept tossed around: feature bits, ags, ippers, switches and the like. There seems no generally accepted name yet. — Martin Fowler
  3. 3. SIMPLE TOGGLE class AmazingRecipe { public function getSauce() { $useNewRecipe = false; // $useNewRecipe = true; if ($useNewRecipe) { // new formula here } else { // original code here } } }
  4. 4. TRADITIONAL FEATURE FLAGS ARE… FLAWED ...ACTUALLY PRETTY USEFUL AND NOT REALLY FLAWED PER SE, BUT THEY COME WITH A FEW CHALLENGES AND I THINK WE CAN IMPROVE THE MODEL, SO LET'S MAKE THEM BETTER
  5. 5. SIMPLE TOGGLE class AmazingRecipe { public function getSauce() { $useNewRecipe = false; // $useNewRecipe = true; if ($useNewRecipe) { // new formula here } else { // original code here } } } ❌ ❌ Not Testable
  6. 6. SIMPLE TOGGLE V2 class AmazingRecipe { public function getSauce() { if ($this->useNewRecipe()) { // new formula here } else { // original code here } } public function useNewRecipe() { return false; // true } } ← ← Can Be Stubbed
  7. 7. MOCK TOGGLE /** * @dataProvider newFormulaProvider */ public function testGetSauce($useNew, $sauce) { $sut = $this->getMock('AmazingRecipe', ['useNewRecipe']); $sut->expects($this->once()) ->method('useNewRecipe') ->will($this->returnValue($useNew)); $this->assertEquals($sauce, $sut->getSauce()); } public function newFormulaProvider() { return [ [ false, 'old Recipe' ], [ true, 'new Recipe' ] ]; }
  8. 8. SIMPLE TOGGLE V2 class AmazingRecipe { public function getSauce() { if ($this->useNewRecipe()) { // new formula here } else { // original code here } } public function useNewRecipe() { return false; // true } } ❌❌❌ Not Maintainable Not Con gurable Not My Concern
  9. 9. FEATURE ROUTER class AmazingRecipe { public function getSauce() { if ($this->useNewRecipe()) { // new formula here } else { // original code here } } public function useNewRecipe() { return Flags::enabled('AmazingRecipie.NewSauceFormula'); } }
  10. 10. FEATURE ROUTER final class Flags { protected static $map = []; public static function enabled($key) { if (empty(static::$map)) { // hydrate map } return !empty(static::$map[$key]); } }
  11. 11. TRADITIONAL FEATURE FLAG SYSTEM Curb Long-Lived Feature Branches Easy To Use (If This Then That) Testable Tons of Applications Continuous Delivery Timed Releases Operations Toggles
  12. 12. WHAT'S NOT TO LIKE?
  13. 13. CYCLOMATIC COMPLEXITY public function getSauce() { if ($this->useNewRecipe()) { if ($this->testSpicyVersion()) { // add spice } if ($this->fixEnabled()) { // fix bug in new code } } else { // original code here if ($this->fixEnabled()) { // fix bug in old code } } } Complexity: 5
  14. 14. ALL OR NOTHING
  15. 15. CANARY DEPLOYMENTS
  16. 16. COHORTS […] a cohort is a group of subjects who have shared a particular event together during a particular time span. — Wikipedia
  17. 17. MORE CONDITIONS? if ( Flags::enabled('SomeFeature') && $user->canSeeFeature('SomeFeature') ) { // execute feature code } class User { public function canSeeFeature($feature) { // check the db or user session? } }
  18. 18. INTRODUCING SWIVEL Swivel can enable features for a subset of users. No more complex control ow; Swivel takes care of determining code paths.
  19. 19. BASIC CONCEPTS 1. Segment users into 10 cohorts. Swivel calls these Buckets. 2. Associate a Feature to a number of active Buckets. 3. Write code that runs when a particular Feature is enabled. 4. Group Features under common Parent Feature to toggle multiple at once. NewExperience NewExperience.NavLinks NewExperience.Dashboard NewExperience.Pro le
  20. 20. SEGMENT USERS INTO BUCKETS id user_id bucket_id 1 160 6 2 956 2 3 189 7 4 412 2
  21. 21. ASSOCIATE FEATURES TO BUCKETS id slug buckets 1 "AwesomeSauce" "1,2,3,4" 2 "AwesomeSauce.Spicy" "1,2" 3 "AwesomeSauce.Saucy" "3,4"
  22. 22. BOOTSTRAP $bucket = 5; // From Session or DB $map = [ 'AwesomeSauce' => [1,2,3,4], 'AwesomeSauce.Spicy' => [1,2], 'AwesomeSauce.Saucy' => [3,4] ]; $config = new ZumbaSwivelConfig($map, $bucket); $swivel = new ZumbaSwivelManager($config);
  23. 23. TOGGLE EXAMPLE class AmazingRecipe { public function __construct(ZumbaSwivelManager $swivel) { $this->swivel = $swivel; } public function getSauce() { return $this->swivel->forFeature('AwesomeSauce') ->addBehavior('Spicy', [$this, 'getSpicyFormula']) ->addBehavior('Saucy', [$this, 'getSaucyFormula']) ->defaultBehavior([$this, 'getFormula']) ->execute(); } protected function getSpicyFormula() { } protected function getSaucyFormula() { } protected function getFormula() { } }
  24. 24. METRICS FOR CANARY DEPLOYMENTS
  25. 25. SWIVEL LOGGING PSR-3 LOGGER AWARE $config = new ZumbaSwivelConfig($map, $bucket, $psr3Logger); // or $config->setLogger($psr3Logger);
  26. 26. SWIVEL METRICS STATSD STYLE METRICS INTERFACE interface MetricsInterface { public function count($context, $source, $value, $metric); public function decrement($context, $source, $metric); public function endMemoryProfile($context, $source, $metric); public function endTiming($context, $source, $metric); public function gauge($context, $source, $value, $metric); public function increment($context, $source, $metric); public function memory($context, $source, $memory, $metric); public function set($context, $source, $value, $metric); public function setNamespace($namespace); public function startMemoryProfile($context, $source, $metric); public function startTiming($context, $source, $metric); public function time($context, $source, Closure $func, $metric); public function timing($context, $source, $value, $metric); }
  27. 27. METRICS FOR A/B TESTING
  28. 28. COMPLEXITY
  29. 29. TRADITIONAL FEATURE FLAGS PROS Eliminate Long Lived Branches Disable Problematic Code CONS Complexity Bump All Or Nothing
  30. 30. COHORT FEATURE FLAGS PROS Eliminate Long Lived Branches Disable Problematic Code Roll Out Features A/B Testing CONS Complexity Bump All Or Nothing
  31. 31. SWIVEL FEATURE FLAGS PROS Eliminate Long Lived Branches Disable Problematic Code Roll Out Features A/B Testing Built In Logging Built In Metrics CONS Complexity Bump
  32. 32. QUESTIONS?
  33. 33. GO FORTH AND TOGGLE! Twitter: @young_steveo Lanyrd: http://lanyrd.com/2016/syntaxcon/sfbqxr Swivel: https://github.com/zumba/swivel Swiveljs: https://github.com/zumba/swiveljs Swivel Cake: https://github.com/zumba/swivel-cake THANKS!

×