Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Flag Your Features with Rollout and Degrade

Flag Your Features with Rollout and Degrade

In light of James Golick's recent untimely passing, here's a brief overview of rollout (https://github.com/FetLife/rollout) and degrade (https://github.com/jamesgolick/degrade), 2 gems which provide a simple interface for dynamic activation and deactivation of your app's features. We'll discuss why we might want to use feature flags and how to implement them using James' gems.

Links:
https://github.com/jamesgolick/degrade/blob/master/lib/degrade.rb#L12-L20
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

Ariel Caplan

January 13, 2015
Tweet

More Decks by Ariel Caplan

Other Decks in Programming

Transcript

  1. WHAT ARE FEATURE FLAGS? • Turn bits of code on

    and off • On/Off • This/That
  2. • Experimental Code • Syncing apps in an SOA ecosystem

    WHY FEATURE FLAGS? Client Service v1 v2
  3. WHY FEATURE FLAGS? • Experimental Code • Syncing apps in

    an SOA ecosystem • Consuming internal services (where you don’t have control) Client Service v1 v2
  4. • 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
  5. • 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?
  6. ROLLOUT REQUIRES REDIS rollout = Rollout.new(redis) ! ! Technically it

    doesn’t require redis… but use it anyway.
  7. 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)
  8. 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
  9. 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
  10. #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
  11. [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) } )
  12. 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
  13. 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) } )