Slide 1

Slide 1 text

Feature Flags Simon Willison, @simonw ! PyCon 2014

Slide 2

Slide 2 text

“Release early, release often”

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

https://www.flickr.com/photos/dottiemae/5236273049/

Slide 5

Slide 5 text

A way of exposing features to a sub-set of your userbase

Slide 6

Slide 6 text

Decouple deployment from release

Slide 7

Slide 7 text

(+ risk-free instant rollback)

Slide 8

Slide 8 text

FEATURE_FLAGS = {! 'mapbox': 'Uses MapBox maps rather than Google Maps',! }!

Slide 9

Slide 9 text

class FeatureFlag(Model):! slug = SlugField(unique = True)! description = CharField(max_length = 140)! enabled_for_all = BooleanField(default = False)

Slide 10

Slide 10 text

class FeatureFlag(Model):! slug = SlugField(unique = True)! description = CharField(max_length = 140)! enabled_for_all = BooleanField(default = False)! users = ManyToManyField(User)!

Slide 11

Slide 11 text

class FeatureFlag(Model):! slug = SlugField(unique = True)! description = CharField(max_length = 140)! enabled_for_all = BooleanField(default = False)! users = ManyToManyField(User)! groups = ManyToManyField(Group)

Slide 12

Slide 12 text

def is_enabled(self, user):! return (! self.enabled_for_all or! self.users.filter(pk = user.pk).exists() or! self.groups.filter(users__pk = user.pk).exists()! )!

Slide 13

Slide 13 text

@flag_required('topic_tracking')! def topic_track(request, slug):! # ... view code ... !

Slide 14

Slide 14 text

if user.has_flag('topic_tracking'):! # ...!

Slide 15

Slide 15 text

{% flag new_eventbrite %}!

Lanyrd is an Eventbrite company

! {% endflag %}!

Slide 16

Slide 16 text

{% flagactive login_facebook %}(alpha-only){% endflagactive %}

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

In read_only_mode • Prevent logged-in user actions • Auth middleware ignores user cookie • Mobile app APIs ignore user token • Shows the banner and hide the “sign in” link

Slide 19

Slide 19 text

MySQL on EC2 PostgreSQL on SoftLayer with no downtime

Slide 20

Slide 20 text

Feature flags at Eventbrite

Slide 21

Slide 21 text

Gargoyle

Slide 22

Slide 22 text

• User / Staff • Event • Organizer • API key • Country • IP address (or range) • eventbrite.com v.s. .de v.s. .fr

Slide 23

Slide 23 text

class RequestCountry(ConditionSet):! country = String(label='Country')! def can_execute(self, instance):! return isinstance(instance, (HttpRequest,))! ! def get_field_value(self, request, field_name):! if field_name == 'country':! return getattr(request, 'country')! ! gargoyle.register(RequestCountry())

Slide 24

Slide 24 text

Gotchas • Unexpected flag combinations • Old feature flag code • Performance!

Slide 25

Slide 25 text

Gargoyle performance • Switch = DB row with JSON blob of conditions • Caches switches in local memory AND remote cache • At Eventbrite, we run memcached on every frontend server to reduce network traffic

Slide 26

Slide 26 text

Meanwhile, at Facebook…

Slide 27

Slide 27 text

Meanwhile, at Facebook… 500M+ gatekeeper checks/second - back in 2012!

Slide 28

Slide 28 text

https://www.flickr.com/photos/capcase/4970062156/

Slide 29

Slide 29 text

• Use feature flags, not long-lived branches! • The ROI on feature flags is ridiculous • Try Gargoyle (or Gutter), or roll your own