Feature Toggling mit umgebungsbasierter Config
Die einfachste Art, a halbfertiges Feature in Produktion zu bringen, ohne es zum Offenlegn, is a die am häufigsten schlecht neu erfundene: a Boolean, aus da Config glesn, in am if gprüft. Bevor du zu am Feature-Flag-Service mit Dashboard und SDK greifst, zahlt si's aus zu wissn, wia weit a einfacher umgebungsbasierter Toggle dich tatsächlich bringt - und des is weiter, ois de meisten Teams annehmen.
Da Kerngedanke
A Feature Toggle is a Laufzeit-Check, der entscheidet, ob a Codepfad ausgführt wird. Der Wert vom Flag kummt von außerhalb vom Code - Umgebungsvariablen, a Config-Datei, a Datenbankzeile -, sodass du's Verhalten ändern kannst, ohne neichn Deploy.
const features = {
newCheckoutFlow: process.env.FEATURE_NEW_CHECKOUT === 'true',
betaExportApi: process.env.FEATURE_EXPORT_API === 'true',
};
function handleCheckout(req, res) {
if (features.newCheckoutFlow) {
return handleCheckoutV2(req, res);
}
return handleCheckoutV1(req, res);
}
Des is der gesamte Mechanismus. Olles andere - prozentuale Rollouts, Targeting pro Nutzer, Notausschalter - is Verfeinerung obendrauf auf "an Wert lesn und drauf verzweigen".
Warum der Aufwand, statt einfach das Feature zu deployn
- Deploy vom Release entkoppeln. Code hinter ana Flag auf
falsemergen und deployn, dann separat einschaltn - ohne Deploy -, wennst wirklich bereit bist. Des macht aus Releasen a Config-Änderung statt a Code-Änderung, wos schneller zum Machn und schneller zum Rückgängigmachn is. - Notausschalter. Wenn a neicher Codepfad in Produktion spinnt, is a Flag ausschaltn sofort wirksam. Einen Deploy zurückrollen dauert länger und macht olles in dem Deploy rückgängig, ned nur des kaputte Feature.
- Umgebungsspezifisches Verhalten. A Feature im Staging wochenlang vor da Produktion einschaltn, ohne an eigenen Branch zu pflegen.
A Config-Schicht, de über a Handvoll Booleans hinaus skaliert
process.env.FEATURE_X === 'true'-Checks quer durch die Codebasis zu streun funktioniert für zwoa Flags und wird bei zehn unwartbar. Zentralisier's:
// config/features.js
function bool(name, fallback = false) {
const value = process.env[name];
if (value === undefined) return fallback;
return value === 'true' || value === '1';
}
module.exports = {
newCheckoutFlow: bool('FEATURE_NEW_CHECKOUT'),
betaExportApi: bool('FEATURE_EXPORT_API'),
strictRateLimit: bool('FEATURE_STRICT_RATE_LIMIT', true), // defaults on
};
Jetzt importiert jede Aufrufstelle von oam Ort, jedes Flag hot oane Zeiln, de seinen Default dokumentiert, und a Flag hinzuzufügen is a Einzeiler-Änderung.
const features = require('./config/features');
if (features.betaExportApi) {
app.use('/api/export', exportRouter);
}
Flags behandeln, de Targeting pro Nutzer brauchen
Umgebungsvariablen sand global - jeder Request auf dem Prozess sieht den söbn Wert. Des passt für "is des Feature überhaupt in Produktion live", aber ned für "zeig des 5 % der Nutzer" oda "zeig des nur internen Accounts". Dafür braucht der Flag-Check a Stückl Request-Kontext:
function isEnabledForUser(flagName, user) {
if (!features[flagName]) return false;
// internal accounts always see flags that are otherwise off for everyone
if (user?.isInternal) return true;
// deterministic percentage rollout: same user always gets the same bucket
const bucket = hashToPercent(`${flagName}:${user.id}`);
return bucket < rolloutPercent(flagName);
}
function hashToPercent(input) {
let hash = 0;
for (let i = 0; i < input.length; i++) {
hash = (hash * 31 + input.charCodeAt(i)) >>> 0;
}
return hash % 100;
}
Das wichtige Detail is, dass hashToPercent pro Nutzer deterministisch is, ned zufällig pro Request - a Nutzer in den 5 % soit bei jedem Request drin bleibn, sonst kriagst a inkonsistente Erfahrung (neiche UI bei oam Seitnaufruf, oide beim nächsten), de Nutzer verwirrt und aus am Bug-Report unmöglich zum Debuggn is.
Wo Flags zum Sterben hingehn
Der Fehlermodus von Feature Flags is ned das Hinzufügen - es is, sie nie zum Entfernen. A Flag, des seit sechs Monaten in jeder Umgebung auf true steht, is totes Gewicht: a Branch, dessen false-Seitn niemand mehr testet, a Bedingung, de jeder künftige Leser im Kopf auswerten muass, und a Quelle für "wart, is der Code überhaupt erreichbar?" beim Debuggn.
Behandl a Flag ois temporäres Konstrukt mit erwarteter Lebensdauer:
- Nenn's nach dem Feature, ned nach da Ticketnummer (
newCheckoutFlow, nedPROJ-4821) - es soit nach am Joar noch selbsterklärend sei. - Wenn a Flag a Weile ohne Zwischenfälle in Produktion auf 100 % steht, is des a Ticket zum Löschen vom Flag und vom oidn Codepfad, ka Dauerzustand.
- Flags, de wirklich dauerhaft gmeint sand (a Ops-Notausschalter, a Pro-Umgebung-Toggle), sand a andere Kategorie - benenn und dokumentier sie anders, damit niemand versucht, sie "aufzuräumen".
Wenn Umgebungsvariablen nimma reichen
Reine umgebungsbasierte Flags stoßen an a echte Decke: Eins zu ändern verlangt immer no, die Deploy-Umgebung anzufassn (a Redeploy, oda zumindest an Prozess-Neustart, um den neichn Wert zu übernehmen), und es gibt ka Audit-Log, wer wos wann umgschaltet hot. Do verdient a dedizierter Flag-Service (LaunchDarkly, Unleash, oda a einfache Flags-Tabelle in deiner eigenen Datenbank mit Admin-UI) seine Komplexität - sofortiges Umschoitn ohne Deploy, Regeln pro Nutzer ohne selbstgbautes Hashing, und a Änderungshistorie.
Greif aber ned schon am ersten Tag dazu. A Dutzend Umgebungsvariablen, über a klans Config-Modul glesn, tragen a Projekt bequem a lange Zeit, und das Konzept vom Flag (a Name, a Boolean, Aufrufstellen, de's prüfen) später auf an echten Flag-Service zu migriern, is a mechanische Änderung, ka Neugestaltung.
Fazit
A Feature Flag is nur a if, dessen Bedingung außerhalb vom Code lebt. Zentralisier die Checks, mach prozentuale Rollouts pro Nutzer deterministisch, und - der Teil, den jeder überspringt - lösch Flags tatsächlich, sobois sie sich bei 100 % eingspielt hom. Die Infrastruktur, um Flags im großen Stil zu verwalten, is optional; die Disziplin, sie zu entfernen, ned.