DEV Community

Cover image for Deploying code and releasing a feature are two different days
Dominique Siacci for GoodBarber

Posted on

Deploying code and releasing a feature are two different days

Everything we run ships continuously. The engine behind the apps, the back office our customers build in, the web products around them — code moves to production at the rhythm of engineering: when it's ready, it goes.

Features don't work that way. A feature has a launch: a name, documentation, support people who know it exists, sometimes a price. That's a product decision, with its own calendar, made by people who don't merge code.

So the two acts had to be decoupled, and the thing that decouples them is the humblest object in software: a flag. Deploying code is an engineering act. Releasing a feature is a product decision. On a platform where every app runs on an engine all apps share, you don't get to conflate the two — there is no "just ship it to some users" when a deployment, by construction, reaches everyone.

Weeks in production before existing

There's nothing exotic about a feature flag — any team that ships continuously runs some version of this, and we claim no invention here. But the day-to-day of it is still worth telling, because it's where the two calendars become visible.

A feature we shipped recently spent weeks in production before it existed. One configuration value kept it off, globally — for everyone except the few people building it, who used it daily, in real conditions, in the middle of real traffic, while every other visitor saw nothing.

When launch day came, nothing was deployed. One value changed. The code had been to production dozens of times by then; the feature went once. That's the whole point of the separation: the code's path to production and the feature's path to users never had to share a schedule — so neither had to wait for the other, and neither could rush the other.

The unit of release is a project

When a feature does start to exist, it advances project by project. That's the natural granularity of a platform: a feature turns on for internal test projects first — some capabilities live for a while in builds that never leave the office — then for a few real projects, then for everyone.

We never had to bolt a feature-flag system onto the product. Switching features on and off per project has been part of the platform's architecture from the start — the switchboard was there long before we ever thought of it as a release strategy.

And sometimes the granularity gets embarrassingly concrete. Somewhere in our codebase there is a condition that checks whether the current project is one of exactly two hardcoded IDs. Two IDs, in the code, letting two projects do something nobody else can. Not proud of it, not ashamed of it: it's a flag in its crudest possible form, doing exactly what flags do. And note what even this crudest flag is not: a separate version. Those two projects run the same engine as everyone else — the exception is a condition inside shared code, never a copy drifting away. Why we never fork that engine is a story of its own, for another day.

The flag and the setting are the same plumbing

Here's the part that is more specific to a platform like ours — a symmetry we get to see both sides of daily.

What we call a feature flag and what our customers call a setting are the same plumbing. When a builder switches comments on for their app, they flip a boolean over code that was delivered long ago — precisely what we do when we release a feature. The engine permanently runs ahead of the product: code for a capability can be fully deployed while the capability doesn't exist yet as a product — nothing references it, no screen offers it, defaults keep it inert. The day it launches, what's new isn't code. What's new is that the configuration now has a place for it.

Push that logic to the end and you get a fair description of the whole platform: an app is a configuration that lights up parts of an engine. The engine's job is to keep every part worth lighting up — the configuration's job is to decide which, and when.

What a flag can't say

There is one thing no flag can express: we're not sure yet.

Some of our features go out wearing a Beta label. Behind that label, at our place, there is no mechanism — no cohort, no computed exit criteria. It's an admission. Humans put it on when a feature is real but young, and humans take it off when the feature has earned it. No threshold fires; someone decides.

A flag separates deployed from released. The label separates released from promised. They look alike — two booleans on the side of the same feature — but one of them governs code, and the other one gives your word.

Top comments (0)