Git branches are often used to write features that take a long time to write. I’m starting to think that they may not be the ideal solution.
Issues with Git branches
A branch might be worked on for weeks then finally merged to the main branch when it’s done. Almost every team I’ve worked on runs into the same issues with long-running branches:
💣 They get out-of-sync — Branches will require regularly merging in changes from main. Devs tend to avoid this chore, making things worse.
💣 They’re impossible to review — Long-running branches often live as pull requests with thousands of lines.
💣 They’re difficult to revert — If any issues arise after merging into production, features may need to be “undeployed.” This is easy with git revert until more code piles up to make it impractical.
Alternative: feature flags
These conditionals are often called feature flags or feature toggles. I’ll list down a few ways I know of implementing feature flags, starting with the simplest (level 0) to the more advanced (level 7).
Level 0: Hiding UI in production
NODE_ENV (Node.js) or RAILS_ENV (Ruby on Rails).Caveats to note
💣 Testing can be difficult — this makes the new features available in tests, and toggling these in unit tests means having to hijack environment variables somehow.
💣 Features also show up in dev mode — config-based checks are often preferred over environment checks for this reason.
✨ Next, let’s organise mutiple flags with configuration.
Level 1: Per-feature configuration
Common conventions include environment variables (shown below) or YAML configuration files.
Caveats to note
💣 URL’s can still be guessed — while it’s often enough to hide links to new features, some new URL routes may also need to be hidden.
✨ Next, let’s secure the app’s URL routes.
Level 2: Suppressing the routes
Caveats to note
💣 Features aren’t available in production — This is often what we want at first, but at some point it would be nice for the internal team to try the feature out in production.
✨ Next, let’s try enabling the feature for a limited set of users.
Level 3: User flags
Caveats to note
💣 User accounts are required — This makes this method not suitable for features not requiring users to sign in, or sites without authentication.
💣 Requires database storage — While it’s easy for some apps to store metadata for a user (eg, an admin flag), this might not always be the case.
✨ Next, let’s look at a possible solution that might remove the need for state storage.
Level 4: Cookies
Caveats to note
💣 May be difficult to enable — Developers may know their way around adding new cookies, but non-technical people may need something more user-friendly.
💣 Can be prone to tampering — Some users will be able enable features if the cookie names leak out.
✨ Next, let’s try to make this a bit more user-friendly.
Level 5: UI for setting cookies
Major browsers today have a secret page to allow enabling experimental features. Something like this can also be done for web apps, possibly hidden by authentication.
about:flags page for experimental features.Caveats to note
💣 Can be prone to tampering — clever users will be able enable features if the cookie names leak out.
✨ Next, let’s try to prevent unauthorised users from enabling feature flags.
Level 6: Signed cookies
cookies.signed appends the payload with an HMAC signature, similar to JWT tokens.