Slide 1

Slide 1 text

No content

Slide 2

Slide 2 text

Michael Heap

Slide 3

Slide 3 text

Don’t leave, pleeeaaaasseee

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

Fun with Country Flags! Presented by @mheap at #nephp

Slide 10

Slide 10 text

Fun with Country Flags! Presented by @mheap at #nephp

Slide 11

Slide 11 text

Fun with Country Flags! Presented by @mheap at #nephp

Slide 12

Slide 12 text

Fun with Country Flags! Presented by @mheap at #nephp

Slide 13

Slide 13 text

Fun with Feature Flags! Presented by @mheap at #nephp

Slide 14

Slide 14 text

Michael @mheap Developer Relations NexmoDev

Slide 15

Slide 15 text

Fun with Feature Flags! Presented by @mheap at #nephp

Slide 16

Slide 16 text

Today’s Plan

Slide 17

Slide 17 text

1. What are feature flags? 2. Implementation 3. Flag management 4. Tips and tricks 5. Conclusion

Slide 18

Slide 18 text

1. What are feature flags? 2. Implementation 3. Flag management 4. Tips and tricks 5. Conclusion

Slide 19

Slide 19 text

1. What are feature flags? 2. Implementation 3. Flag management 4. Tips and tricks 5. Conclusion

Slide 20

Slide 20 text

1. What are feature flags? 2. Implementation 3. Flag management 4. Tips and tricks 5. Conclusion

Slide 21

Slide 21 text

1. What are feature flags? 2. Implementation 3. Flag management 4. Tips and tricks 5. Conclusion

Slide 22

Slide 22 text

Feature Flags?

Slide 23

Slide 23 text

Feature Toggles?

Slide 24

Slide 24 text

Feature Flip?

Slide 25

Slide 25 text

Feature Gate?

Slide 26

Slide 26 text

Feature Switches?

Slide 27

Slide 27 text

Separate feature release from code deployment

Slide 28

Slide 28 text

http://code.flickr.net/2009/12/02/flipping-out/

Slide 29

Slide 29 text

No content

Slide 30

Slide 30 text

No content

Slide 31

Slide 31 text

Feature flags aren’t new

Slide 32

Slide 32 text

#ifdef NEW_ALGORITHM NEW_ALGORITHM(input) #else ALGORITHM(input) #endif $ make build -DNEW_ALGORITHM

Slide 33

Slide 33 text

./make_call.sh --use-new-algorithm ./make_call.sh --use-original-algorithm

Slide 34

Slide 34 text

if (in_array($user->id, $whitelistedUsers)) { return $service->useNewAlgorithm($input); } return $service->useAlgorithm($input);

Slide 35

Slide 35 text

I love a good history lesson

Slide 36

Slide 36 text

Use Cases?

Slide 37

Slide 37 text

1. Permissions

Slide 38

Slide 38 text

1. Permissions 2. Early-access

Slide 39

Slide 39 text

1. Permissions 2. Early-access 3. Opt-in

Slide 40

Slide 40 text

1. Permissions 2. Early-access 3. Opt-in 4. Incremental roll-out

Slide 41

Slide 41 text

1. Permissions 2. Early-access 3. Opt-in 4. Incremental roll-out 5. Block users

Slide 42

Slide 42 text

1. Permissions 2. Early-access 3. Opt-in 4. Incremental roll-out 5. Block users 6. Calendar driven

Slide 43

Slide 43 text

1. Permissions 2. Early-access 3. Opt-in 4. Incremental roll-out 5. Block users 6. Calendar driven 7. Kill switch

Slide 44

Slide 44 text

1. Permissions 2. Early-access 3. Opt-in 4. Incremental roll-out 5. Block users 6. Calendar driven 7. Kill switch 8. Power user

Slide 45

Slide 45 text

1. Permissions 2. Early-access 3. Opt-in 4. Incremental roll-out 5. Block users 6. Calendar driven 7. Kill switch 8. Power user 9. Maintenance

Slide 46

Slide 46 text

1. Permissions 2. Early-access 3. Opt-in 4. Incremental roll-out 5. Block users 6. Calendar driven 7. Kill switch 8. Power user 9. Maintenance 10. Sunset

Slide 47

Slide 47 text

No content

Slide 48

Slide 48 text

Flag Types

Slide 49

Slide 49 text

Release Toggles Ops Toggles Flag Classes Permission Toggles Experiment Toggles

Slide 50

Slide 50 text

Release Toggles Ops Toggles Flag Classes Permission Toggles Experiment Toggles Lifetime Days Dynamism Per deployment

Slide 51

Slide 51 text

Release Toggles Ops Toggles Flag Classes Permission Toggles Experiment Toggles Lifetime Days - Weeks Dynamism Human Controlled

Slide 52

Slide 52 text

Release Toggles Ops Toggles Flag Classes Permission Toggles Experiment Toggles Lifetime Years Dynamism Per Request

Slide 53

Slide 53 text

Release Toggles Ops Toggles Flag Classes Permission Toggles Experiment Toggles Lifetime Weeks - Months Dynamism Per Request

Slide 54

Slide 54 text

https://martinfowler.com/articles/feature-toggles.html

Slide 55

Slide 55 text

Ownership Release toggles owned by devs Ops toggles owned by ops Permission toggles Experiment toggles owned by product

Slide 56

Slide 56 text

No content

Slide 57

Slide 57 text

Flag Granularity

Slide 58

Slide 58 text

On/Off Switch Enable or disable entirely

Slide 59

Slide 59 text

On/Off Switch Percentage of users Enable or disable entirely Toggle for a percentage of users

Slide 60

Slide 60 text

On/Off Switch Percentage of users Individuals Enable or disable entirely Toggle for a percentage of users Toggle for specific users

Slide 61

Slide 61 text

On/Off Switch Percentage of users Individuals Groups Enable or disable entirely Toggle for a percentage of users Toggle for specific users Enable for specific groups e.g. Power Users

Slide 62

Slide 62 text

On/Off Switch Percentage of users Individuals Groups Request information Enable or disable entirely Toggle for a percentage of users Toggle for specific users Enable for specific groups e.g. Power Users Enable for specific request headers or bodies

Slide 63

Slide 63 text

No content

Slide 64

Slide 64 text

Implementation

Slide 65

Slide 65 text

Build vs Buy

Slide 66

Slide 66 text

1. Dashboard

Slide 67

Slide 67 text

1. Dashboard 2. Access control

Slide 68

Slide 68 text

1. Dashboard 2. Access control 3. Complex rules

Slide 69

Slide 69 text

1. Dashboard 2. Access control 3. Complex rules 4. Cascading flags

Slide 70

Slide 70 text

1. Dashboard 2. Access control 3. Complex rules 4. Cascading flags 5. Multivariate rules

Slide 71

Slide 71 text

1. Dashboard 2. Access control 3. Complex rules 4. Cascading flags 5. Multivariate rules 6. Auditing

Slide 72

Slide 72 text

1. Dashboard 2. Access control 3. Complex rules 4. Cascading flags 5. Multivariate rules 6. Auditing 7. Speed

Slide 73

Slide 73 text

1. Dashboard 2. Access control 3. Complex rules 4. Cascading flags 5. Multivariate rules 6. Auditing 7. Speed 8. Scale

Slide 74

Slide 74 text

1. Dashboard 2. Access control 3. Complex rules 4. Cascading flags 5. Multivariate rules 6. Auditing 7. Speed 8. Scale 9. 100% uptime

Slide 75

Slide 75 text

Build

Slide 76

Slide 76 text

Qandidate Toggle $manager = new ToggleManager(new InMemoryCollection()); $afterSix = new GreaterThanEqual(18); $beforeTen = new LessThanEqual(22); $conditions = []; $conditions[] = new OperatorCondition('time', $afterSix); $conditions[] = new OperatorCondition('time', $beforeTen); $toggle = new Toggle('disable-work-email', $conditions, Toggle::STRATEGY_UNANIMOUS); $manager->add($toggle); $context = new Context(); $context->set('time', (int) date('G')); echo 'Everyone is ' . ($manager->active('disable-work-email', $context)) ? ‘happy!' : 'sad :(';

Slide 77

Slide 77 text

Qandidate Toggle $manager = new ToggleManager(new InMemoryCollection()); $afterSix = new GreaterThanEqual(18); $beforeTen = new LessThanEqual(22); $conditions = []; $conditions[] = new OperatorCondition('time', $afterSix); $conditions[] = new OperatorCondition('time', $beforeTen); $toggle = new Toggle('disable-work-email', $conditions, Toggle::STRATEGY_UNANIMOUS); $manager->add($toggle); $context = new Context(); $context->set('time', (int) date('G')); echo 'Everyone is ' . ($manager->active('disable-work-email', $context)) ? ‘happy!' : 'sad :(';

Slide 78

Slide 78 text

Qandidate Toggle $manager = new ToggleManager(new InMemoryCollection()); $afterSix = new GreaterThanEqual(18); $beforeTen = new LessThanEqual(22); $conditions = []; $conditions[] = new OperatorCondition('time', $afterSix); $conditions[] = new OperatorCondition('time', $beforeTen); $toggle = new Toggle('disable-work-email', $conditions, Toggle::STRATEGY_UNANIMOUS); $manager->add($toggle); $context = new Context(); $context->set('time', (int) date('G')); echo 'Everyone is ' . ($manager->active('disable-work-email', $context)) ? ‘happy!' : 'sad :(';

Slide 79

Slide 79 text

Qandidate Toggle $manager = new ToggleManager(new InMemoryCollection()); $afterSix = new GreaterThanEqual(18); $beforeTen = new LessThanEqual(22); $conditions = []; $conditions[] = new OperatorCondition('time', $afterSix); $conditions[] = new OperatorCondition('time', $beforeTen); $toggle = new Toggle('disable-work-email', $conditions, Toggle::STRATEGY_UNANIMOUS); $manager->add($toggle); $context = new Context(); $context->set('time', (int) date('G')); echo 'Everyone is ' . ($manager->active('disable-work-email', $context)) ? ‘happy!' : 'sad :(';

Slide 80

Slide 80 text

Qandidate Toggle $manager = new ToggleManager(new InMemoryCollection()); $afterSix = new GreaterThanEqual(18); $beforeTen = new LessThanEqual(22); $conditions = []; $conditions[] = new OperatorCondition('time', $afterSix); $conditions[] = new OperatorCondition('time', $beforeTen); $toggle = new Toggle('disable-work-email', $conditions, Toggle::STRATEGY_AFFIRMATIVE); $manager->add($toggle); $context = new Context(); $context->set('time', (int) date('G')); echo 'Everyone is ' . ($manager->active('disable-work-email', $context)) ? ‘happy!' : 'sad :(';

Slide 81

Slide 81 text

Qandidate Toggle $manager = new ToggleManager(new InMemoryCollection()); $afterSix = new GreaterThanEqual(18); $beforeTen = new LessThanEqual(22); $conditions = []; $conditions[] = new OperatorCondition('time', $afterSix); $conditions[] = new OperatorCondition('time', $beforeTen); $toggle = new Toggle('disable-work-email', $conditions, Toggle::STRATEGY_MAJORITY); $manager->add($toggle); $context = new Context(); $context->set('time', (int) date('G')); echo 'Everyone is ' . ($manager->active('disable-work-email', $context)) ? ‘happy!' : 'sad :(';

Slide 82

Slide 82 text

Qandidate Toggle $manager = new ToggleManager(new InMemoryCollection()); $afterSix = new GreaterThanEqual(18); $beforeTen = new LessThanEqual(22); $conditions = []; $conditions[] = new OperatorCondition('time', $afterSix); $conditions[] = new OperatorCondition('time', $beforeTen); $toggle = new Toggle('disable-work-email', $conditions, Toggle::STRATEGY_AFFIRMATIVE); $manager->add($toggle); $context = new Context(); $context->set('time', (int) date('G')); echo 'Everyone is ' . ($manager->active('disable-work-email', $context)) ? ‘happy!' : 'sad :(';

Slide 83

Slide 83 text

Qandidate Toggle $manager = new ToggleManager(new InMemoryCollection()); $afterSix = new GreaterThanEqual(18); $beforeTen = new LessThanEqual(22); $conditions = []; $conditions[] = new OperatorCondition('time', $afterSix); $conditions[] = new OperatorCondition('time', $beforeTen); $toggle = new Toggle('disable-work-email', $conditions, Toggle::STRATEGY_UNANIMOUS); $manager->add($toggle); $context = new Context(); $context->set('time', (int) date('G')); echo 'Everyone is ' . ($manager->active('disable-work-email', $context)) ? ‘happy!' : 'sad :(';

Slide 84

Slide 84 text

Qandidate Toggle $manager = new ToggleManager(new InMemoryCollection()); $afterSix = new GreaterThanEqual(18); $beforeTen = new LessThanEqual(22); $conditions = []; $conditions[] = new OperatorCondition('time', $afterSix); $conditions[] = new OperatorCondition('time', $beforeTen); $toggle = new Toggle('disable-work-email', $conditions, Toggle::STRATEGY_UNANIMOUS); $manager->add($toggle); $context = new Context(); $context->set('time', (int) date('G')); echo 'Everyone is ' . ($manager->active('disable-work-email', $context)) ? ‘happy!' : 'sad :(';

Slide 85

Slide 85 text

Qandidate Toggle $manager = new ToggleManager(new InMemoryCollection()); $afterSix = new GreaterThanEqual(18); $beforeTen = new LessThanEqual(22); $conditions = []; $conditions[] = new OperatorCondition('time', $afterSix); $conditions[] = new OperatorCondition('time', $beforeTen); $toggle = new Toggle('disable-work-email', $conditions, Toggle::STRATEGY_UNANIMOUS); $manager->add($toggle); $context = new Context(); $context->set('time', (int) date('G')); echo 'Everyone is ' . ($manager->active('disable-work-email', $context)) ? ‘happy!' : 'sad :(';

Slide 86

Slide 86 text

$manager = new ToggleManager(new InMemoryCollection()); $afterSix = new GreaterThanEqual(18); $beforeTen = new LessThanEqual(22); $conditions = []; $conditions[] = new OperatorCondition('time', $afterSix); $conditions[] = new OperatorCondition('time', $beforeTen); $toggle = new Toggle('disable-work-email', $conditions); $manager->add($toggle); Configuration: Code

Slide 87

Slide 87 text

Configuration: Array $data = array( 'some-feature' => array( 'name' => 'toggling', 'conditions' => array( array( 'name' => 'operator-condition', 'key' => 'user_id', 'operator' => array('name' => 'greater-than', 'value' => 41), ), ), ), ); $serializer = new InMemoryCollectionSerializer(); $collection = $serializer->deserialize($data); $manager = new ToggleManager($collection);

Slide 88

Slide 88 text

Configuration: JSON/YAML $yaml = <<deserialize($array); $manager = new ToggleManager($collection);

Slide 89

Slide 89 text

Configuration: Redis $predis = new Predis\Client(); $collection = new PredisCollection('toggle_demo', $predis); $manager = new ToggleManager($collection);

Slide 90

Slide 90 text

Qandidate Toggle API { "conditions" : [ { "name" : "operator-condition", "operator" : { "name" : "less-than", "value" : "1337" }, "key" : "user_id" } ], "name" : "foo", "status" : "conditionally-active", "originalName" : "foo" } PUT /toggles/{name} https://github.com/qandidate-labs/qandidate-toggle-api

Slide 91

Slide 91 text

Qandidate Toggle UI https://github.com/qandidate-labs/qandidate-toggle-ui

Slide 92

Slide 92 text

Build (Pros) 1. Free! 2. Total control 3. Complex rules 4. API and UI available

Slide 93

Slide 93 text

Build (Cons) 1. Self hosted 2. PHP only 3. Complex rules

Slide 94

Slide 94 text

Buy

Slide 95

Slide 95 text

No content

Slide 96

Slide 96 text

Multi-Language

Slide 97

Slide 97 text

Prebuilt Dashboard

Slide 98

Slide 98 text

Environment Aware

Slide 99

Slide 99 text

Scaleable

Slide 100

Slide 100 text

Audit Log

Slide 101

Slide 101 text

A/B Testing

Slide 102

Slide 102 text

ld-relay

Slide 103

Slide 103 text

Buy (Pros) 1. Lovely dashboard 2. Multi-language 3. Built in audit log 4. Environment aware 5. A/B testing conversion tracking

Slide 104

Slide 104 text

Buy (Cons) 1. It costs (at least) $79/month 2. Can’t modify the product 3. Dependent on 3rd party

Slide 105

Slide 105 text

Build vs Buy

Slide 106

Slide 106 text

So. Much. Choice

Slide 107

Slide 107 text

It depends

Slide 108

Slide 108 text

Show me code

Slide 109

Slide 109 text

Slide 110

Slide 110 text

Slide 111

Slide 111 text

public function onKernelRequest($event) { $flag = $event->getRequest->attributes->get('_flag'); $alt = $event->getRequest->attributes->get('_alt'); if ($toggleManager->active($flag, $context)) { $event->getRequest->attributes->set('controller', $alt); } } profile: path: /profile/{user} defaults: _controller: AcmeBundle:Profile:update _alt: AcmeBundle:NewProfile:update _flag: new-profile-controller

Slide 112

Slide 112 text

{% if feature_is_active('new-profile-image-picker') %} {# Show new picker #} {% else %} {# Use old flash-based picker #} {% endif %}

Slide 113

Slide 113 text

toggleManager->active('enhanced-audio', $context)) { return new EnhancedAudioStreamProcessor($args); } return new BasicAudioStreamProcessor($args); } }

Slide 114

Slide 114 text

Controller View Factory Enable a route for specific users Show different UI elements Branch by abstraction for refactoring

Slide 115

Slide 115 text

No content

Slide 116

Slide 116 text

Toggle Configuratin

Slide 117

Slide 117 text

Hard Coded Change the code Dynamic Static

Slide 118

Slide 118 text

Hard Coded Deploy Config Change the code Deploy your application Dynamic Static

Slide 119

Slide 119 text

Hard Coded Deploy Config Parameterised Config Change the code Deploy your application Edit config, restart app Dynamic Static

Slide 120

Slide 120 text

Hard Coded Deploy Config Parameterised Config Database Config Change the code Deploy your application Edit config, restart app Edit via UI Dynamic Static

Slide 121

Slide 121 text

Hard Coded Deploy Config Parameterised Config Database Config Distributed Config Change the code Deploy your application Edit config, restart app Edit via UI e.g. Consul or Zookeeper Dynamic Static

Slide 122

Slide 122 text

Feature Dashboard

Slide 123

Slide 123 text

Flag State

Slide 124

Slide 124 text

Role Based Access

Slide 125

Slide 125 text

Audit Log

Slide 126

Slide 126 text

Non-technical Users

Slide 127

Slide 127 text

Technical Debt

Slide 128

Slide 128 text

DON’T

Slide 129

Slide 129 text

Cleanup based on activity

Slide 130

Slide 130 text

Cleanup based on activity

Slide 131

Slide 131 text

Create & Cleanup

Slide 132

Slide 132 text

WIP limits

Slide 133

Slide 133 text

Expiration date

Slide 134

Slide 134 text

Explosion date

Slide 135

Slide 135 text

Tips & Tricks

Slide 136

Slide 136 text

Testing Flags

Slide 137

Slide 137 text

Testing Flags Feature A Feature B ✅ ✅ ✅ ☠ ☠ ✅ ☠ ☠

Slide 138

Slide 138 text

Testing Flags Feature A Feature B Feature C ✅ ✅ ✅ ✅ ☠ ✅ ✅ ✅ ☠ ☠ ✅ ✅ ✅ ☠ ☠ ☠ ✅ ☠ ☠ ☠ ✅ ☠ ☠ ☠

Slide 139

Slide 139 text

Testing Flags Feature A Feature B Feature C Feature D ✅ ✅ ✅ ✅ ✅ ✅ ✅ ☠ ✅ ✅ ☠ ✅ ✅ ☠ ✅ ✅ ☠ ✅ ✅ ✅ ✅ ✅ ☠ ☠ ✅ ☠ ✅ ☠ ✅ ☠ ☠ ✅ ☠ ✅ ✅ ☠ ☠ ✅ ☠ ✅ ☠ ☠ ✅ ✅ ✅ ☠ ☠ ☠ ☠ ✅ ☠ ☠ ☠ ☠ ✅ ☠ ☠ ☠ ☠ ✅ ☠ ☠ ☠ ☠

Slide 140

Slide 140 text

Testing Flags Number of flags Possible permutations 2 4 3 8 4 16 5 32 10 1024 25 33,554,432 50 1.12589991E+15 100 1.2676506E+30

Slide 141

Slide 141 text

Homepage Carousel Homepage CTA ✅ ✅ ✅ ☠ ☠ ✅ ☠ ☠ Forum Edit Permission Forum Delete Permission ✅ ✅ ✅ ☠ ☠ ✅ ☠ ☠ Upload Profile Image ✅ ☠ New Interesting Algorithm ✅ ☠ High Post Length ✅ ☠ Show Debug Info? ✅ ☠ Enable Audit Log ✅ ☠ Auto Logout ✅ ☠ API Access API v2 ✅ ✅ ✅ ☠ ☠ ✅ ☠ ☠

Slide 142

Slide 142 text

Expose State { "api_v2": true, "audit_log": true, "new_recommendation_algo": false } GET /toggle_status

Slide 143

Slide 143 text

Flag Descriptions basic-rec-algo: true

Slide 144

Slide 144 text

Flag Descriptions basic-rec-algo: enabled: true description: Use a simplistic recommendation algorithm. This is fast and produces less load on backend systems, but is way less accurate than our standard algorithm.

Slide 145

Slide 145 text

Clear Naming allow_user_delete and allow_user_edit not user_control

Slide 146

Slide 146 text

Audit Log Feature State User Date allow_user_edit ✅ Sarah 2018-05-11 12:22:08 enhanced_rec_algo ✅ Ashley 2018-05-04 15:33:16 allow_user_signup ☠ Ashley 2018-05-04 15:27:33 enhanced_rec_algo ☠ system:load_manager 2018-05-04 15:16:30 allow_user_signup ✅ Bob 2018-05-04 15:12:01 enable_api ✅ Sarah 2018-04-30 09:56:59

Slide 147

Slide 147 text

Fail Safe Do positively enable features e.g. enable-ibm- analysis, enhanced-recomendation-algo Don’t use flags for suppressing new features e.g. disable-shiny-new-feature

Slide 148

Slide 148 text

Conclusion

Slide 149

Slide 149 text

Woooooooo

Slide 150

Slide 150 text

Flags are great!

Slide 151

Slide 151 text

Ops Toggles Release Toggles Flag Classes Permission Toggles Experiment Toggles

Slide 152

Slide 152 text

Build vs Buy

Slide 153

Slide 153 text

Qandidate Toggle

Slide 154

Slide 154 text

No content

Slide 155

Slide 155 text

One More Thing

Slide 156

Slide 156 text

No Reuse

Slide 157

Slide 157 text

Knight Capital

Slide 158

Slide 158 text

High frequency trader

Slide 159

Slide 159 text

No content

Slide 160

Slide 160 text

No content

Slide 161

Slide 161 text

Mistakes were made

Slide 162

Slide 162 text

Knight Capital 1. Reused flags

Slide 163

Slide 163 text

Knight Capital 1. Reused flags 2. Didn’t delete obsolete code

Slide 164

Slide 164 text

Knight Capital 1. Reused flags 2. Didn’t delete obsolete code 3. Couldn’t be disabled without a deployment

Slide 165

Slide 165 text

Knight Capital 1. Reused flags 2. Didn’t delete obsolete code 3. Couldn’t be disabled without a deployment 4. The deploy actually enabled the old code on all 8 servers, instead of disabling it

Slide 166

Slide 166 text

$460m Gone

Slide 167

Slide 167 text

@mheap / @NexmoDev [email protected]