Slide 1

Slide 1 text

FLAG YOUR FEATURES WITH ROLLOUT AND DEGRADE Ariel Caplan

Slide 2

Slide 2 text

WHAT ARE FEATURE FLAGS? • Turn bits of code on and off • On/Off • This/That

Slide 3

Slide 3 text

• Experimental Code • Syncing apps in an SOA ecosystem WHY FEATURE FLAGS? Client Service v1 v2

Slide 4

Slide 4 text

WHY FEATURE FLAGS? • Experimental Code • Syncing apps in an SOA ecosystem • Consuming internal services (where you don’t have control) Client Service v1 v2

Slide 5

Slide 5 text

• Experimental Code • Syncing apps in an SOA ecosystem • Consuming internal services (where you don’t have control) • Consuming external services (which experience downtime) WHY FEATURE FLAGS? Client Service

Slide 6

Slide 6 text

• Experimental Code • Syncing apps in an SOA ecosystem • Consuming internal services (where you don’t have control) • Consuming external services (which experience downtime) • Debugging tools WHY FEATURE FLAGS?

Slide 7

Slide 7 text

ROLLOUT REQUIRES REDIS rollout = Rollout.new(redis) ! ! Technically it doesn’t require redis… but use it anyway.

Slide 8

Slide 8 text

ACTIVATION/DEACTIVATION # activate for all users rollout.activate(:chat) ! # deactivate for all users rollout.deactivate(:chat)

Slide 9

Slide 9 text

A/B TESTING # activate for a percentage of users rollout.activate_percentage(:chat, 20) ! # check if the user gets the new feature! rollout.active?(:chat, User.first)

Slide 10

Slide 10 text

WHERE TO INSERT BRANCH POINTS?

Slide 11

Slide 11 text

BRANCH POINT: CONTROLLER class ExperimentalController < ApplicationController ! def index if rollout.active?(:my_feature) @entities = MyFeature.get_entities(params) respond_with @entities else head(:service_unavailable) end end ! end

Slide 12

Slide 12 text

BRANCH POINT: MODELS class ResponseFormatter ! attr_reader :array ! def initialize(array) @array = array end ! def output if rollout.active?(:safe_json_format) { 'array' => array } else array end end ! end

Slide 13

Slide 13 text

#PROTIP: USE HUBOT class FeaturesController < ApplicationController ! def update rollout.activate(params[:id].to_sym) head :ok end ! def destroy rollout.deactivate(params[:id].to_sym) head :ok end ! end

Slide 14

Slide 14 text

PART II: DEGRADE “Because Stuff Doesn’t Work!”™

Slide 15

Slide 15 text

[OPTIONAL] SETTINGS APLENTY! degrade_my_feature = Degrade.new( redis, name: :my_feature, sample: 5000, minimum: 100, threshold: 0.1, errors: [StandardError], failure_strategy: -> { rollout.deactivate(:my_feature) } )

Slide 16

Slide 16 text

WRAP YOUR UNRELIABLE SERVICES if rollout.active?(:my_feature) data = degrade_my_feature.perform do Net::HTTP.get('mega-downtime.com', '/data.json') end end

Slide 17

Slide 17 text

DEGRADE DOESN’T AFFECT YOUR CODE def perform begin mark_request yield rescue *@errors => e mark_failure raise e end end https://github.com/jamesgolick/degrade/blob/master/lib/degrade.rb#L12-L20

Slide 18

Slide 18 text

PIMP MY FAILURE STRATEGY degrade_my_feature = Degrade.new( redis, name: :my_feature, failure_strategy: -> { rollout.deactivate(:my_feature) OutageNotifier.notify(downtime: :my_feature) MyFeatureActivatorWorker.perform_in(30.minutes) } )

Slide 19

Slide 19 text

JAMES GOLICK http://jamesgolick.com/ https://news.ycombinator.com/ item?id=8804624 https://medium.com/ @benkaufman/remembering- james-golick-23c1dc3ab920 https://medium.com/@jill380/the- adventurous-life-of-james-golick- bda4a33137b6

Slide 20

Slide 20 text

Ariel Caplan @amcaplan amcaplan.ninja
 


Slide 21

Slide 21 text

Ariel Caplan @amcaplan amcaplan.ninja
 
 Thank you to: YOU!