Feature Flags: Kontrolliertes Ausrollen | Enjyn Gruppe
Hallo Welt
Hallo Welt
Original Lingva Deutsch
Übersetzung wird vorbereitet...
Dieser Vorgang kann bis zu 60 Sekunden dauern.
Diese Seite wird erstmalig übersetzt und dann für alle Besucher gespeichert.
0%
DE Zurück zu Deutsch
Übersetzung durch Lingva Translate

235 Dokumentationen verfügbar

Wissensdatenbank

Feature Flags Implementierung

Zuletzt aktualisiert: 20.01.2026 um 10:05 Uhr

Feature Flags: Kontrolliertes Ausrollen

Feature Flags ermöglichen sichere Deployments und graduelle Rollouts. Lernen Sie, wie Sie Features kontrolliert aktivieren.

Was sind Feature Flags?

// Ohne Feature Flag
function checkout() {
    processPayment();
}

// Mit Feature Flag
function checkout() {
    if (featureFlags.isEnabled('new_payment_flow')) {
        processNewPayment();
    } else {
        processPayment();
    }
}

// Vorteile:
// - Deployment ≠ Release
// - Schnelles Rollback (Flag aus)
// - A/B Testing
// - Canary Releases

Flag-Typen

Typ Beschreibung Lebensdauer
Release Flag Feature ein/ausschalten Kurz (nach Rollout löschen)
Experiment Flag A/B Tests Mittel (bis Entscheidung)
Ops Flag Circuit Breaker, Kill Switch Lang/permanent
Permission Flag Feature für User-Gruppen Lang/permanent

Einfache Implementierung

// featureFlags.js
class FeatureFlags {
    constructor() {
        this.flags = new Map();
    }

    // Flag definieren
    define(name, options = {}) {
        this.flags.set(name, {
            enabled: options.enabled ?? false,
            percentage: options.percentage ?? 100,
            users: options.users ?? [],
            groups: options.groups ?? []
        });
    }

    // Flag prüfen
    isEnabled(name, context = {}) {
        const flag = this.flags.get(name);
        if (!flag) return false;

        // Komplett deaktiviert
        if (!flag.enabled) return false;

        // Spezifische User
        if (flag.users.length && context.userId) {
            if (flag.users.includes(context.userId)) return true;
        }

        // User-Gruppen
        if (flag.groups.length && context.userGroup) {
            if (flag.groups.includes(context.userGroup)) return true;
        }

        // Prozentuale Ausrollung
        if (flag.percentage < 100 && context.userId) {
            const hash = this.hashString(name + context.userId);
            return (hash % 100) < flag.percentage;
        }

        return flag.enabled;
    }

    hashString(str) {
        let hash = 0;
        for (let i = 0; i < str.length; i++) {
            hash = ((hash << 5) - hash) + str.charCodeAt(i);
            hash |= 0;
        }
        return Math.abs(hash);
    }
}

// Verwendung
const flags = new FeatureFlags();

flags.define('new_checkout', {
    enabled: true,
    percentage: 10  // 10% der User
});

flags.define('beta_features', {
    enabled: true,
    groups: ['beta_testers', 'internal']
});

// In Code
if (flags.isEnabled('new_checkout', { userId: user.id })) {
    // Neuer Checkout
}

Konfiguration über Umgebung

// Config aus Environment
const featureConfig = {
    new_checkout: {
        enabled: process.env.FF_NEW_CHECKOUT === 'true',
        percentage: parseInt(process.env.FF_NEW_CHECKOUT_PERCENT) || 0
    },
    dark_mode: {
        enabled: process.env.FF_DARK_MODE === 'true'
    }
};

// JSON Config Datei
// features.json
{
    "new_checkout": {
        "enabled": true,
        "percentage": 25,
        "groups": ["beta"]
    },
    "experimental_search": {
        "enabled": true,
        "users": ["user_123", "user_456"]
    }
}

Feature Flag Service (LaunchDarkly-Style)

// Server
class FeatureFlagService {
    constructor(config) {
        this.flags = new Map(Object.entries(config));
        this.overrides = new Map();
    }

    evaluate(flagKey, context) {
        // Override prüfen
        const overrideKey = `${flagKey}:${context.userId}`;
        if (this.overrides.has(overrideKey)) {
            return this.overrides.get(overrideKey);
        }

        const flag = this.flags.get(flagKey);
        if (!flag) return { value: false, reason: 'FLAG_NOT_FOUND' };

        // Evaluierung
        if (!flag.enabled) {
            return { value: false, reason: 'DISABLED' };
        }

        // Targeting Rules
        for (const rule of flag.rules || []) {
            if (this.matchesRule(rule, context)) {
                return { value: rule.value, reason: 'RULE_MATCH' };
            }
        }

        // Percentage Rollout
        if (flag.percentage < 100) {
            const bucket = this.getBucket(flagKey, context.userId);
            if (bucket >= flag.percentage) {
                return { value: false, reason: 'PERCENTAGE_ROLLOUT' };
            }
        }

        return { value: true, reason: 'DEFAULT' };
    }

    // Override für Testing
    setOverride(flagKey, userId, value) {
        this.overrides.set(`${flagKey}:${userId}`, { value, reason: 'OVERRIDE' });
    }

    getBucket(flagKey, userId) {
        const hash = crypto.createHash('md5')
            .update(`${flagKey}:${userId}`)
            .digest('hex');
        return parseInt(hash.substring(0, 8), 16) % 100;
    }
}

React Integration

// FeatureFlagProvider.jsx
import { createContext, useContext } from 'react';

const FeatureFlagContext = createContext();

export function FeatureFlagProvider({ flags, children }) {
    const isEnabled = (flagName) => {
        return flags[flagName]?.enabled ?? false;
    };

    return (
        <FeatureFlagContext.Provider value={{ isEnabled, flags }}>
            {children}
        </FeatureFlagContext.Provider>
    );
}

export function useFeatureFlag(flagName) {
    const { isEnabled } = useContext(FeatureFlagContext);
    return isEnabled(flagName);
}

// Verwendung
function CheckoutButton() {
    const newCheckout = useFeatureFlag('new_checkout');

    if (newCheckout) {
        return <NewCheckoutButton />;
    }
    return <LegacyCheckoutButton />;
}

// Oder als Component
function FeatureFlag({ name, children, fallback = null }) {
    const enabled = useFeatureFlag(name);
    return enabled ? children : fallback;
}

<FeatureFlag name="new_dashboard" fallback={<OldDashboard />}>
    <NewDashboard />
</FeatureFlag>

Graduelle Rollouts

# Canary Release Plan
Tag 1:  1% der User  → Monitoring
Tag 2:  5% der User  → Monitoring
Tag 3:  25% der User → Monitoring
Tag 4:  50% der User → Monitoring
Tag 5:  100% aller User

# Bei Problemen: Sofort auf 0% zurück

Best Practices

✅ Do:
  • Flags nach Rollout entfernen (Tech Debt!)
  • Konsistente Naming-Convention
  • Dokumentieren wofür jeder Flag ist
  • Default immer "aus" (sicher)
❌ Don't:
  • Flags ewig behalten
  • Verschachtelte Flag-Logik
  • Flags in kritischen Pfaden ohne Fallback

Weitere Informationen

Enjix Beta

Enjyn AI Agent

Hallo 👋 Ich bin Enjix — wie kann ich dir helfen?
120