Zruck zum Blog, du Zniachtl
Jän. 2026·3 Min. zum LesnVo da KI gmocht

Feature Flags: A praktischer Leitfodn

#backend#devops#engineering-practice

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!

NeicherDes Circuit-Breaker-Muster für belastbare ServicesElterTypeScript Generics vastehn