Deploy vs Release: Warum Progressive Delivery zwei Dinge trennt, die du für identisch gehalten hast

Dein Team hat gerade einen neuen Checkout-Ablauf fertiggestellt. Der Code ist getestet, der Pull-Request gemerged und die Deployment-Pipeline grün. Du drückst auf Deploy. Die neue Version geht in Produktion. Jetzt sieht jeder Nutzer den neu gestalteten Button, die umgestellten Formularfelder und den neuen Bestätigungsbildschirm.

Aber was, wenn du sehen möchtest, wie sich der neue Ablauf verhält, bevor du ihn allen zeigst? Was, wenn du nur 5 % der Nutzer zuerst testen lassen und dann basierend auf echten Daten ausweiten möchtest?

In den meisten Teams passieren Deploy und Release gleichzeitig. Wenn neuer Code auf dem Server landet, werden die darin enthaltenen Funktionen für die Nutzer sichtbar. Aber diese beiden Aktionen müssen nicht miteinander verbunden sein. Sie zu trennen gibt dir eine Kontrollmöglichkeit, die deine Denkweise über das Ausliefern von Software verändert.

Deploy ist technisch. Release ist erfahrungsbasiert.

Deploy ist der Vorgang, Code auf einen Server zu bringen. Es ist eine technische Operation. Du erstellst ein Artefakt, überträgst es in eine Umgebung und startest die neue Version. Der Server führt nun den neuen Code aus.

Release ist der Vorgang, eine Funktion für Nutzer verfügbar zu machen. Es ist eine erfahrungsbasierte Entscheidung. Der Code läuft bereits auf dem Server, aber die Funktion ist hinter einem Schalter versteckt. Wenn du den Schalter umlegst, sehen die Nutzer das neue Verhalten.

Derselbe Deploy kann mehrere nicht freigegebene Funktionen enthalten. Du kannst einmal deployen und schrittweise releasen. Du kannst eine Funktion auch für eine Nutzergruppe freigeben, für eine andere jedoch nicht – alles aus derselben laufenden Version der Anwendung.

Das folgende Diagramm veranschaulicht die Trennung:

flowchart TD A[Code gemerged] --> B[Deploy auf Server] B --> C[Gesamter Code läuft auf Server] C --> D{Feature-Flag-Prüfung} D -- Flag an --> E[Release der Funktion an Nutzer] D -- Flag aus --> F[Funktion für Nutzer versteckt] E --> G[Metriken überwachen] G --> H{Daten positiv?} H -- Ja --> I[Ausrollung erweitern %] H -- Nein --> J[Flag deaktivieren] I --> K[Vollständiges Release] K --> L[Flag aus Code entfernen] J --> F

Diese Trennung ist die Grundlage von Progressive Delivery.

Ein konkretes Beispiel

Stell dir vor, dein Team hat einen neuen „Jetzt kaufen"-Button entwickelt. Er ist größer, farbenfroher und prominenter platziert. Das Team ist vom Code überzeugt, aber unsicher, wie bestehende Nutzer reagieren werden. Eine plötzliche Layout-Änderung könnte Menschen verwirren, die seit Monaten die alte Oberfläche nutzen.

Mit Progressive Delivery gehst du wie folgt vor:

  1. Du deployest die neue Version in Produktion. Der neue Button-Code läuft auf dem Server, ist aber versteckt. Die Nutzer sehen den alten Button.
  2. Du konfigurierst dein Feature-Flag-System so, dass der neue Button 5 % der Nutzer angezeigt wird. Diese Nutzer werden zufällig ausgewählt.
  3. Nach einer Woche prüfst du die Daten. Nutzer, die den neuen Button sahen, haben Käufe häufiger abgeschlossen. Es wurden keine Verwirrungen gemeldet.
  4. Du erhöhst die Ausrollung auf 50 % der Nutzer. Eine weitere Woche vergeht. Die Daten sehen weiterhin gut aus.
  5. Du rollst die Funktion für 100 % der Nutzer aus. Die Funktion ist jetzt vollständig live.

Beachte, was passiert ist: ein Deploy, mehrere Releases. Der Code ging einmal in Produktion. Die Funktion wurde schrittweise sichtbar, gesteuert durch echtes Nutzerverhalten.

Feature Flags sind der Mechanismus

Um Deploy und Release zu trennen, brauchst du Feature Flags. Ein Feature Flag ist ein bedingter Zweig in deinem Code, der prüft, ob eine Funktion für den aktuellen Nutzer aktiv sein soll. Das Flag wird extern gesteuert, normalerweise über einen Konfigurationsdienst oder eine spezielle Feature-Flag-Plattform.

Ein einfaches Feature Flag sieht im Code so aus:

if feature_flags.is_active("new_checkout_button", user_id):
    render_new_button()
else:
    render_old_button()

Das Flag kann ohne neues Deployment umgeschaltet werden. Du änderst die Konfiguration, und die nächste Anfrage dieses Nutzers zeigt das neue Verhalten. Keine Code-Änderung, kein Build, kein Deploy.

Feature Flags ermöglichen auch Experimente. Du kannst A/B-Tests durchführen, indem du verschiedene Nutzersegmente zu unterschiedlichen Feature-Varianten führst. Eine Gruppe sieht einen roten Button, eine andere einen blauen. Die Daten zeigen dir, welche Variante besser funktioniert.

Wie sich das von Canary und Staged Rollout unterscheidet

Canary-Deployment und Staged Rollout leiten Nutzer zu verschiedenen Versionen der Anwendung. Du betreibst zwei Versionen parallel, und ein Load Balancer leitet einen Prozentsatz des Datenverkehrs an die neue Version. Wenn etwas schiefgeht, leitest du den Datenverkehr zurück zur alten Version.

Progressive Delivery funktioniert anders. Du betreibst eine Version der Anwendung. Alle Nutzer treffen auf dieselben Server. Aber innerhalb dieser Version sehen verschiedene Nutzer unterschiedliche Funktionen. Die Trennung erfolgt auf Funktionsebene, nicht auf Anwendungsebene.

Diese Unterscheidung ist wichtig, wenn du eine Funktion unabhängig von anderen Änderungen im selben Deploy freigeben möchtest. Mit Canary kannst du den neuen Button nicht für 5 % der Nutzer freigeben, während der Rest der neuen Version versteckt bleibt. Du sendest Nutzer entweder an die neue oder die alte Version. Mit Progressive Delivery steuerst du jede Funktion einzeln.

Die Kosten von Feature Flags

Feature Flags sind nicht kostenlos. Jedes Flag fügt deinem Code einen bedingten Zweig hinzu. Mit der Zeit sammeln sich Flags an. Wenn du sie nicht aufräumst, füllt sich deine Codebasis mit toten Bedingungen, die die Logik schwerer lesbar und testbar machen.

Ein übliches Muster ist, ein Flag für eine Funktion zu verwenden, sie zu validieren, vollständig auszurollen und das Flag dann im nächsten Sprint zu entfernen. Aber Teams vergessen diesen Schritt oft. Das Flag bleibt im Code, und niemand erinnert sich, was es steuert oder ob es noch aktiv ist.

Disziplin ist hier entscheidend. Behandle Feature Flags standardmäßig als temporär. Wenn eine Funktion für alle Nutzer vollständig freigegeben ist, plane die Aufräumarbeiten ein. Wenn du eine Feature-Flag-Plattform verwendest, bieten die meisten Tools Dashboards, die anzeigen, welche Flags vollständig ausgerollt und zur Entfernung bereit sind.

Wann Progressive Delivery sinnvoll ist

Nicht jedes Team braucht Progressive Delivery. Wenn deine Anwendung klein ist, deine Nutzerbasis homogen und deine Funktionen einfach sind, ist der Overhead von Feature Flags möglicherweise nicht gerechtfertigt.

Aber Progressive Delivery wird wertvoll, wenn:

  • Du Funktionen auslieferst, die das Nutzerverhalten signifikant verändern.
  • Du eine große oder vielfältige Nutzerbasis hast, bei der die Reaktionen variieren.
  • Du Funktionen mit echten Daten validieren möchtest, bevor du sie vollständig freigibst.
  • Dein Team häufig releast und die Deployment-Frequenz vom Release-Zeitpunkt entkoppeln möchte.

Die entscheidende Erkenntnis ist, dass Progressive Delivery einen Mittelweg zwischen „an alle ausliefern" und „gar nicht ausliefern" bietet. Du kannst den Code ausliefern, die Auswirkungen beobachten und das Release auf Basis von Beweisen ausweiten.

Eine praktische Checkliste für die Einführung von Progressive Delivery

Wenn du dich entscheidest, Deploy und Release zu trennen, sind hier die Schritte für den Einstieg:

  • Wähle eine Funktion aus, die von einer schrittweisen Freigabe profitieren würde. Starte nicht mit jeder Funktion.
  • Füge ein Feature Flag für diese Funktion hinzu. Verwende eine einfache Konfigurationsdatei oder einen dedizierten Dienst.
  • Deploye den Code mit deaktiviertem Flag. Überprüfe, ob die Funktion versteckt ist.
  • Aktiviere das Flag für einen kleinen Prozentsatz der Nutzer. Überwache Metriken und Logs.
  • Erhöhe den Prozentsatz basierend auf den Daten. Wenn etwas schiefgeht, deaktiviere das Flag sofort.
  • Wenn die Funktion vollständig ausgerollt ist, entferne das Flag aus dem Code.

Das Fazit

Deploy und Release sind nicht dasselbe. Deploy bedeutet, Code auf Server zu bringen. Release bedeutet, Funktionen für Nutzer sichtbar zu machen. Progressive Delivery trennt diese beiden Aktionen, sodass du Code nach deinem Zeitplan ausliefern und Funktionen nach dem Zeitplan der Daten freigeben kannst.

Wenn dein Team das nächste Mal eine Funktion abschließt, frage: Müssen wir das jetzt an alle freigeben, oder lassen wir die Daten entscheiden?