Feature Flags in a Design System: a true love story
As some of you might know, v11 has been a huge initiative for the Carbon team for well over a year now, involving every single team member working to improve so many different moving parts of the Carbon ecosystem. While thinking about how we wanted to build, create and iterate on features without disrupting the workflow of our community, and minimizing the disruption of ours, we decided to use feature flags.
Why a feature flag:
Our team has been dynamically involved in the development v11, but that also hasn’t stopped us from attending to our everyday work around the design system. We release every two weeks, with fixes to bug reports, feature requests, or a11y enhancements. With a continuous two week release cadence, running in parallel to our v11 work, we needed a workflow strategy that would allow us to work on new features as a team, and still work together on everyday issues — thank you feature flags.
Our team uses trunk based development, working off of a single main branch. While we are all introducing a complexity of new features, feature flags help us prevent potential merge conflicts and broken builds. We are able to test features locally, and build them out incrementally.
While planning for v11 and its release, we didn’t want to be bombarded with future merge conflicts or have to keep track of multiple feature branches created by different squads within the team.
As a design system, we also have to be careful about the changes we make to our codebase. We don’t want to accidentally introduce any breaking changes to our users (that would suck) or unintentionally release unstable features (that would also suck). With a feature flag we can keep unstable features shielded behind a flag from our community.
Feature flags allow us to safely write and test all of the component changes and updates our hearts desire, without the fear of accidentally pushing to production code. Basically, we can break, create and re-write our code, behind the flag, in a controlled environment.
- Reduces risk of introducing breaking changes to our community
- Prevents potential merge conflicts within the mono-repo
- Avoids potentially breaking any builds
- Allows us to stay organized, without managing multiple feature branches
- Allows us to build out features incrementally
What we decided to flag:
In our major release there are two main categories for our upcoming features: net new and breaking changes.
New features in our v11 release included things like, new color tokens, inline theming, and new components such as Popover, Theme, Tooltip and a few others.
Work on many of these features was done over several sprints, involving a constant feedback loop between design and development. Using a feature flag allows us build out features alongside our designers, get feedback internally, and continue to work incrementally, leading up to our release.
We are able work on features such as prop updates, component refactors, and move from CSS grid to CSS flex-box, by developing them behind a feature flag.
The flexibility of a feature flag, allows us to develop and run these net new and breaking changes, in our main package, alongside our production code, without ever interrupting it. We are able to test and build tools such as CSS flex-box, in a controlled environment before introducing it to our users to be consumed.
- Potential breaking changes
- Net new (release specific) features
To see a list of breaking changes, and net new features that we included in our v11 release — checkout our migration docs here.
User interviews & feedback:
Feature flags have provided us with the flexibility needed around our release, testing and feedback process.
With the release of v11, we developed an incremental release process, that would enable teams to test out new features and provide us with feedback. Through our Release Partner Program, teams have the ability to turn on the feature flag, and test out features that have been recently released. We followed an alpha, beta, etc. release cycle, to fix and improve upon features, before announcing a more formal GA release.
Feature work fell into our two weeks sprints, targeting specific v11 release dates. Learn more about how we have structured our release timeline here.
We want teams testing out new components and potentially breaking changes to feel excited about the value of this new release. For us, that meant making sure this migration was as frictionless as possible. Alongside our Release Partner Program, we conducted a series of user interviews with developers, designers and product managers, from a variety of different teams. We got direct feedback on new features they had tested, code they had implemented, and ways that we could improve our v11 migration experience from previous ones. (ex: v9 — v10).
Our user interview questions boiled down to:
- Do you mind walking us through what your experience has been with the Beta release?
- If there has been an issue with a feature (in early release stages — there more than likely is) → Can you walk us through the challenges of building with X feature?
- What are some improvements we can make while your team is migrating or using X feature?
While we continue to work through the testing and feedback process, using a feature flag gives teams the ability to quickly disable the flag and continue with their as-is Carbon version until we were able to able to move features to a more stable status.
- Perfectly flexible for an incremental release process
- Teams can quickly test, provide feedback, and disable flags as needed
In conclusion:
Feature flags have been an integral part of v11 release strategy. We can create and build features iteratively. Our community can turn on a flag to test, and run features enhancements without disrupting their workflows. We as a team, can switch between work streams by turning the flag off and on. And we can release features incrementally as the are scheduled into our release cycle, without accidentally deploying any risky code.