Proper feature flags #2354

Merged
merged 8 commits into from Jul 9, 2015

Projects

None yet

4 participants

@nickstenning
Member

The way we had implemented feature flags was pretty inflexible, and
wasn't effectively allowing us to do the one thing that feature flags
are really intended to do, namely:

Decouple deployment (when you push code to production) from release
(when users see new features).

A truly effective feature flag system is one which achieves the above,
and also enables more dynamic options for "releasing" such as:

  • release to admin users/beta users only
  • release to a randomly selected 10% of users
  • release only to one specific user

This requires that the feature flag system have some knowledge of the
accounts system.

Furthermore, in order to make the feature flag system truly atomic and
reversible (i.e. shit has gone wrong, let's flip that back) we need to
be able to toggle feature flags instantly, without needing to wait for
an application redeploy.

Both of these requirements indicate a feature flag system fully
integrated with the request-response cycle of the application, and one
where flag status can be more complex than a simple boolean.

In order to make this possible, this commit puts feature flags into a
"feature" table of the main application database. This allows us to
extend the definition of flag state as and when we see fit to enable
some or all of the release options denoted above.

The initial state of all feature flags is off, but in order to
facilitate an easy migration path for us the data migration with this
commit will read the current state of the existing flags from the system
environment and write appropriate rows into the table.

For what it's worth, I've done this work now because it's very important to be able to make an atomic flip from one data store to another (such as a migration from elasticsearch to postgres), which is a piece of work I'm currently planning out.

nickstenning added some commits Jul 8, 2015
@nickstenning nickstenning Remove 'accounts' and 'api' feature flags
These "feature flags" are simply acting as configuration, not as feature
flags (things that could conceivably be toggled on and off on a request
by request basis). Perhaps more importantly, the application cannot
function without the accounts system or API :)
0c69825
@nickstenning nickstenning Enable alembic's autogenerate features
By setting target_metadata correctly we can make migrations more quickly
by simply comparing the schema as defined in code to the schema in the
local database and create the migration with:

    alembic -c conf/alembic.ini revision --autogenerate -m "Some migration"
f84ca57
@tilgovi
Contributor
tilgovi commented Jul 8, 2015

LGTM. You can merge it yourself. I'll leave it to you in case you want to fix any of the lint messages.

@tilgovi
Contributor
tilgovi commented Jul 8, 2015

Tests don't run on travis, though. I don't know what that's about. The feature table not being created automatically?

@nickstenning
Member

Yep, looks like I've screwed something up. Will take a look tomorrow.

@nickstenning
Member

So, the issue with the tests was that building an extension requires templates to be rendered and adding support for dynamic feature toggles now implies that rendering templates requires a database. Joy.

Anyway, as it happens this all goes away with proper dynamic front-end feature flags, so I have extended this PR with the code needed to bring dynamic feature toggles to the client.

I'm not going to merge this myself now, as this is new code and I'd like it to be reviewed, but here's an overview:

  • when this is merged, we can add feature toggles into code that spans frontend and backend, and deploy without any fear of this code being enabled before we're ready to release it
  • we can toggle a feature in the database (and, in due course, in an admin UI) and it will be enabled across backend and frontend code without requiring any new deployment
  • we can even toggle a feature without requiring a page reload on the frontend, as feature flags are only cached on the frontend for 5 minutes
nickstenning added some commits Jul 8, 2015
@nickstenning nickstenning Make feature flags runtime toggles stored in the database
The way we had implemented feature flags was pretty inflexible, and
wasn't effectively allowing us to do the one thing that feature flags
are really intended to do, namely:

> Decouple deployment (when you push code to production) from release
> (when users see new features).

A truly effective feature flag system is one which achieves the above,
and also enables more dynamic options for "releasing" such as:

- release to admin users/beta users only
- release to a randomly selected 10% of users
- release only to one specific user

This requires that the feature flag system have some knowledge of the
accounts system.

Furthermore, in order to make the feature flag system truly atomic and
reversible (i.e. shit has gone wrong, let's flip that back) we need to
be able to toggle feature flags instantly, without needing to wait for
an application redeploy.

Both of these requirements indicate a feature flag system fully
integrated with the request-response cycle of the application, and one
where flag status can be more complex than a simple boolean.

In order to make this possible, this commit puts feature flags into a
"feature" table of the main application database. This allows us to
extend the definition of flag state as and when we see fit to enable
some or all of the release options denoted above.

The initial state of all feature flags is off, but in order to
facilitate an easy migration path for us the data migration with this
commit will read the current state of the existing flags from the system
environment and write appropriate rows into the table.
86eed92
@nickstenning nickstenning Regenerate assets when JavaScript source files change
We have an increasing number of pure-JS source files, and we should
reload when they change, too.
6597cf5
@nickstenning nickstenning Add a route to expose current feature flag values
This will be used by the front-end to establish the current feature flag
state.
bff5006
@nickstenning nickstenning Add a minimal feature client to the front-end
In order to respond to feature flag changes on the frontend, we need a
way of knowing what the current feature flag values are on the backend.

This commit adds a basic feature flag client that retrieves current
feature flag values by making an ajax request to the server. The client
also includes a cache, and supports retrieving new value from the server
when the cache expires.
6fef7f4
@nickstenning nickstenning Use new feature client for dynamic feature toggling
Our first attempt at integrating feature flags with the frontend
required a rebuild and redeploy of the extension, which somewhat
defeats the purpose of feature flags. This commit wires up the new
feature client introduced in the preceding commits, allowing feature
toggles to update behaviour of already-deployed clients.
8f6f9d2
@landscape-bot

Code Health
Repository health increased by 0.07% when pulling 8f6f9d2 on proper-feature-flags into 65b9c3c on master.

@nickstenning
Member

And all three lint errors reported by prospector now are spurious, IMO.

@tilgovi tilgovi Don't rebuild on every request in dev environment
Until we sort the build artifacts out from the source files using
a *.js glob will catch a mixture of source file and build artifacts.
19da938
@tilgovi
Contributor
tilgovi commented Jul 9, 2015

Looks great. Only change I made was to assets.yaml so we're not rebuilding everything all the time in dev.

We should maybe move the final build artifacts about scripts. In other words, h/static/hypothesis.js and h/static/app.js and h/static/app.css or something.

@tilgovi tilgovi merged commit 60b7fba into master Jul 9, 2015

0 of 2 checks passed

continuous-integration/travis-ci/pr The Travis CI build is in progress
Details
continuous-integration/travis-ci/push The Travis CI build is in progress
Details
@tilgovi tilgovi deleted the proper-feature-flags branch Jul 9, 2015
@JakeHartnell
Contributor

Very nice! 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment