Feature Flags: A praktischer Leitfodn
A Feature Flag is a Bedingung um a Stückl Code herum, mit der ma den Code ein- oda ausschoitn kann - für olle, für a Teilmenge vo Nutzern oda schrittweise - ohne a neichs Deployment auszuliefern. De Idee is so einfach, dass's verlockend is, einfach if-Anweisungen durch de Codebasis zum streun, und genau so gehn Feature Flags im großen Stil schief. Gut gmacht entkoppeln's des Deployen vom Code vom Releasen; schlampig gmacht werdn's zu am permanenten Labyrinth aus toten Zweigen, de si koaner zum Löschn traut.
De einfachste mögliche Version
Im Kern is a Feature Flag nur a boolescher Check:
if (flags.isEnabled('new-checkout-flow', { userId: user.id })) {
return renderNewCheckout();
}
return renderLegacyCheckout();
Des Interessante is ned des if - es is flags.isEnabled. Wo kummt de Antwort her, und wia schnö kann sie si ändern?
Drei Arten, a Flag auszuwerten
Statische Config. A JSON- oda YAML-Datei oda Umgebungsvariablen, zur Deploy-Zeit gprüft. Am einfachsten zum Implementiern, aber a Flag zu ändern heißt a Redeploy - und des nimmt an großen Teil vom Sinn weg (schnelles, risikoarmes Umschoitn).
const flags = { 'new-checkout-flow': process.env.FF_NEW_CHECKOUT === 'true' };
A Remote-Flag-Service, zur Laufzeit abgfrogt (und gecacht), sodass a Flag von am Dashboard aus umgschaltet wern kann, ohne die Deploy-Pipeline überhaupt anzufassn:
async function isEnabled(flagKey, context) {
const cached = cache.get(flagKey);
if (cached) return evaluate(cached, context);
const flag = await flagService.fetch(flagKey);
cache.set(flagKey, flag, { ttl: 30_000 });
return evaluate(flag, context);
}
Prozentualer oda attributbasierter Rollout, wo's Flag ned nur an/aus is, sondern a Teil vom Traffic ansteuert - 5 % der Nutzer, oda olle, deren plan === 'enterprise' is:
function evaluate(flag, context) {
if (!flag.enabled) return false;
if (flag.rolloutPercent != null) {
const bucket = hashToPercent(context.userId, flag.key);
return bucket < flag.rolloutPercent;
}
if (flag.rules) {
return flag.rules.every((rule) => matchesRule(rule, context));
}
return true;
}
function hashToPercent(userId, flagKey) {
const hash = simpleHash(`${userId}:${flagKey}`);
return hash % 100;
}
Des hashToPercent-Stückl is wichtiger, ois es ausschaut: Hashen auf userId (statt pro Request zufällig zum würfeln) bedeutet, dass derselbe Nutzer über Seitnaufrufe hinweg konsistent auf der gleichen Seitn vom Flag landet - sonst kunnt a Nutzer bei oam Request den neichn Checkout-Ablauf sehn und beim nächsten den oidn, wos verwirrend is und Bugs fost unmöglich reproduzierbar mocht.
Wofür Flags wirklich da sand
Release-Flags entkoppeln Deploy vom Release: Code gmerged und "dark" ausliefern, dann einschoitn, wennst bereit bist, unabhängig vom nächsten Deploy-Fenster. Experiment-Flags fahrn an A/B-Test - a Prozentsatz der Nutzer kriagt Variante B, und du misst den Unterschied. Ops-Flags sand Notausschalter fürs elegante Degradieren - a langsames, unkritisches Feature (Empfehlungen, a Drittanbieter-Widget) unter Last ohne Deploy obdrahn. Permission-Flags schränken a Feature auf bestimmte Nutzer oda Pläne ein, wia a reines Enterprise-Feature - wobei für langlebige Zugriffskontrolle meistens a ordentliches Entitlement-System besser dient ois a Flag, des eigentlich temporär gmeint woar.
Die Unterscheidung is wichtig, weil jeder Typ an anderen Lebenszyklus hot. Ops-Flags kinnan ewig lebn. Release- und Experiment-Flags soitn des ned.
Der Teil, den jeder überspringt: Löschn
A Flag, des seit sechs Monaten auf 100 % steht und koan Codepfad mehr hot, der des alte Verhalten prüft, bringt koa Sicherheit mehr - es is totes Gewicht, des die Codebasis schwerer lesbar mocht und jede künftige Änderung riskanter, weil's jetzt zwoa Pfade zum Durchdenken gibt statt oam.
// Six months later, this still exists:
if (flags.isEnabled('new-checkout-flow')) {
return renderNewCheckout();
}
return renderLegacyCheckout(); // dead code nobody has run in months, still shipped, still maintained
Behandl Flag-Cleanup ois Teil von da Definition of Done vom Feature, ned ois optionales Nachspiel: Sobois a Flag vollständig ausgerollt und a vernünftige Zeit stabil is, entfern den Flag-Check und den toten Zweig im söbn Rutsch. Monche Teams erzwingen des mit am Linter, der jeden Flag-Check älter ois N Tage anmeckert, oda mit am Dashboard, des Flags zeigt, de lang niemand umgschaltet hot.
A Falle: Flags, de interagiern
Zwoa unabhängig ausschauende Flags kinnan sich zu am Zustand kombiniern, den niemand gtestet hot:
if (flags.isEnabled('new-checkout-flow')) {
if (flags.isEnabled('new-payment-provider')) {
return renderNewCheckoutWithNewPayments(); // did anyone actually test this combination?
}
return renderNewCheckoutWithOldPayments();
}
Jedes zusätzliche Flag verdoppelt de Anzoi an Codepfaden in den Teilen der App, de es berührt. Zwoa Flags sand vier Pfade; drei sand acht. Halt Flags eng gefasst und kurzlebig, und sei bewusst, wöche Kombinationen du wirklich unterstützn muasst - jede Kombination zum Testen is ned realistisch, sobois mehr ois a poar Flags im söbn Codebereich aktiv sand.
Fazit
Feature Flags gebn dir de Möglichkeit, Code auszuliefern, ohne ihn zu releasen, schrittweise auszurollen und a spinnerts Feature ohne Deploy abzudrahn - wirklich wertvolle Eigenschaften. Da Fehlermodus is ned des Flag söba, sondern es ois permanent statt temporär zu behandeln: Jedes Flag, des du dazufügst, is a Schuld, de irgendwann durchs Löschn zruckzahlt wern muass, und a Codebasis, de die Schuld nie zruckzahlt, endet schwerer durchschaubar ois oane ganz ohne Flags. Also raum auf, du Zniachtl!