Continuous Delivery mit Feature Toggles

In vielen Projekten erfolgt die Entwicklung von neuen Features in dem einen oder anderen Branching Modell wie zum Beispiel Git Flow: Features werden zunächst auf einem separaten Branch entwickelt und erst nach „Fertigstellung“ des Features wieder integriert. Beim Mergen der Änderungen kommt es dann gelegentlich zu Konflikten und wenn man Pech hat, landet man in der „Merging Hell“. Moderne VCS wie GIT machen Branching + Merging zwar deutlich einfacher, ändern aber auch nichts daran, dass es gelegentlich schwierig ist, konkurrierende Änderungen zu einem lauffähigen Deployment zu integrieren.

Das Hauptproblem mit Feature Branches ist aber ein anderes: Wann ist ein Feature „fertig“, kann also integriert werden? Erfolgt die Abnahme einer Story auf Basis des Feature Branches, muss nach der Integration eine weitere Qualitätssicherung erfolgen – denn sonst könnten sich Fehler in der Kombination mit parallel entwickelten Features einschleichen. Erfolgt die Qualitätssicherung erst nach der Integration auf einem Release Branch, könnte sich herausstellen, dass das Feature eben doch nicht fertig ist, weil die eine oder andere Anforderung nicht erfüllt ist.

Continuous Integration verfolgt daher einen anderen Weg: die Entwicklung erfolgt auf dem HEAD und jeder Commit wird direkt automatisiert integriert. Jenkins, TeamCity oder andere Tools helfen dabei, regelmässig alle paar Minuten einen aktuellen Build zu erstellen und auf einen CI Server zu deployen. Die Abnahme der Feature erfolgt entweder auf dem CI Server oder einer separaten Stage der Build Pipeline.

Eine sehr gute automatisierte Testabdeckung ist die Voraussetzung dafür, dass die Software jederzeit lauffähig ist und alle Anforderungen erfüllt bleiben.
Feature Toggle stellen sicher, dass ein Feature erst dann aktiviert wird, wenn es fertig und von der Qualitätssicherung abgenommen ist. Dazu werden die neuen Funktionen der Software über einfache if-Statements geschaltet:
if (Features.NEW_FANCY_FEATURE.isActive()) {
        useMyFancyNewFeature();
} else {
        doTheOldBoringStuff()
}
Mit der Verwendung von Feature Toggles erhalten wir ganz neue Möglichkeiten, Funktionen live zu stellen. Features lassen sich nämlich auch über „Ventile“ (Valves, Activation Strategies) graduell aktivieren:
  • Zunächst nur für einzelne User, beispielsweise Tester, Product Owner oder „Friendly Customers“.
  • Für ein Prozent der User, später 50% mit einem A/B Test, der den Erfolg des Features sicherstellt, irgendwann dann für alle User.
  • Zeitlich gesteuert, um bspw. zu einem Release Date scharf zu schalten.
  • Feature lassen sich auch auf nur einem Server des Clusters aktivieren.
  • …und natürlich umgebungsspezifisch für ein oder mehrere Stages der Deployment Pipeline.
Die letzte Entscheidung, ob eine neue Funktion Online geht kann also in der Live Umgebung erfolgen, was dabei hilft, regelmässig und kurz getaktet zu deployen. Im Team „Entdecken“ setzen wir Feature Toggles bereits seit einiger Zeit ein. Aktuell gehen wir alleine in unserem Team (das System besteht aus mehreren lose gekoppelten Anwendungen) mehrmals die Woche, teilweise auch mehrmals am Tag live.

Die Integration von Feature Toggles in die Software ist einfach. Eine rudimentäre Lösung ist schnell selbst entwickelt, es gibt aber auch fertige Lösungen. Wir haben vor einiger Zeit von einer Eigenentwicklung auf die Togglz Library umgestellt: eine schicke, schlanke Library, die sich sehr leicht in alle möglichen Arten von Java-Anwendungen integrieren lässt und auch eine Console zur Verwaltung der Toggle mitbringt. Die oben genannten „Activation Strategies“ werden (unter anderem) unterstützt, es lässt sich leicht eine Rechte-Verwaltung anbinden und auch die Persistenz der Toggle-Einstellungen ist leicht möglich.

Togglz Administration Console

Togglz Administration Console

Toggles verwenden wir dabei in verschiedenen Situationen:
  • Neu entwickelte Features werden zunächst deaktiviert. In den Tests und Test-Umgebungen werden neue Feature aktiv geschaltet.
  • Alle Caches werden über (per default aktivierte) Toggles geschaltet. Sollte es zu Inkonsistenzen der gecachten Daten kommen, lässt sich das Caching deaktivieren.
  • Bestimmte Funktionen werden dauerhaft über Toggles abgesichert: beispielsweise können wir auf diese Weise den Zugriff auf unkritische externe Systeme ausschalten oder gleich die gesamte Personalisierung ausknipsen, so dass nur noch cachebare Seiten ausgeliefert werden.

Die Togglz Library unterstützt derartige Gruppierungen über die FeatureGroup Annotation. Wir haben uns für die verschiedenen Anwendungsfälle eigene Annotationen geschrieben. Features, die noch in der Entwicklung sind, werden beispielsweise über die InDevelopment geschaltet:

@FeatureGroup
@Label("Features in development")
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface InDevelopment {
}

public enum Features implements Feature {
    @Label("Only load product recommendations asynchronously using AJAX")
    @InDevelopment
    USE_AJAX_FOR_PRODUCT_RECOMMENDATIONS,
    ...
In der Togglz Console werden die FeatureGroups als Tabs dargestellt, in denen die zur Gruppe gehörenden Features automatisch einsortiert werden.
An die Entwicklung mit Feature Toggles mussten wir uns erst einmal gewöhnen: Bei zu wenig Toggles können existierende Funktionen durch Seiteneffekte beeinträchtigt werden. Wenn wir es aber übertreiben, leidet die Lesbarkeit und Testbarkeit des Codes. Vor allem aber ist es wichtig, nicht mehr benötigte Toggles auch wieder aus dem Code zu entfernen.
Die Vorteile überwiegen diese anfänglichen Schwierigkeiten jedoch bei weitem. Neben den neuen Möglichkeiten der Livestellung können wir mit Hilfe der Toggles kontinuierlich integrieren und häufig in Produktion gehen. Die Feedback-Zyklen werden auf diese Weise sehr kurz und wir können direkt auf dem HEAD häufige kleine Commits pushen, die aufwändige Merges vermeiden: Ein neuer Test, eine kleine Änderung, ein Commit.
In der Kombination mit BDD, TDD, Build Pipelines, unterbrechungsfreien Deployments und einer rollbackfähigen Anwendung sind wir mit Feature Toggles auf dem besten Weg in Richtung Continuous Delivery.

Guido Steinacker, Jahrgang 1969, Diplom-Informatiker. Nach mehreren Stationen in der Software-Entwicklung verschiedener mittelständischer Unternehmen stieß er 2009 zu OTTO. 2010 entwickelte er im Rahmen von Prototypen die Grundlagen für die neue Shop-Architektur von otto.de und ist mittlerweile als Executive Software-Architekt im Bereich E-Commerce tätig.

Tagged with: , , , , , , , , , , ,
Veröffentlicht in Development
2 comments on “Continuous Delivery mit Feature Toggles
  1. José Stiller sagt:

    Ich hätte noch ein paar Fragen zum Verständnis sofern das erlaubt ist. Falls nicht bzw. wenn ich einfach falsch liege oder eine falsche Annahme mache, bitte gerne korrigieren!

    Am Anfang beschreibst du ein Problem bezüglich der Qualitätssicherung nach der Fertigstellung eines Features. Den Merging Hell lass ich mal außen vor. Ist halt so. Du stellst die Frage wann etwas getestet werden muss. Meiner Meinung nach, wird doch in dem jeweiligem Branch nach Fertigstellung des Features oder idealerweise täglich ein Rebase mit dem Master sowie nach der Fertigstellung des Features ein Rebase mit dem Master durchgeführt. Und da es sich beim Master immer um eine lauffähige Version handelt, könnte man dann doch problemlos auch im Branch testen. Was nun passieren könnte, wäre dass während des Testens sich der Master nochmal verändert hat. Aber wenn man diese Annahme zugrunde legt, müsste man Prinzipiell nach der Fertigstellung eines Features immer alles Testen, da es dann quasi immer Seiteneffekte haben könnte. Daher wahrscheinlich der Schritt Richtung CI um automatisiert testen zu können. Ich nehme mal an, dass die Software ohnehin schon lose gekoppelt war um es generell leicht testen zu können.

    Weiterhin hätte man die Feature Toggles auch unabhängig von allem dem einführen können oder? Denn dann würde ich den Artikel so verstehen, dass man gerne im Sinne von TDD über BDD mit Hilfe von Continuous Integration hin zum Continuous Delivery kommen möchte um unterbrechungsfrei deployen zu können. Und das dabei die Feature Toggles sehr Hilfreich sind und damit eine Neuerung! Oder habe ich das falsch verstanden.

    • Guido Steinacker sagt:

      Hallo José,

      natürlich findet man auch mit einem Branching-Modell einen Weg, Features zu testen, keine Frage. Branches führen aber tendenziell zu etwas längeren Release-Zyklen, als wenn man den CI-Ansatz verfolgt, in dem zumindest theoretisch jeder Commit Livegestellt werden kann. CI und Feature-Branches vertragen sich nicht sonderlich gut miteinander: Wenn man mit Feature-Branches arbeitet, werden die Features auf dem Branch „fertig“gestellt, bevor integriert wird. Die Integration wird dadurch sehr viel grob-granularer, als wenn kontinuierlich integriert wird.
      CI führt zwangsläufig zu einer sehr hohen automatisierten Testabdeckung. Feature-Branches sind in dieser Hinsicht etwas weniger anspruchsvoll. Branches führen eher zu „Releases“, während CI in Richtung Continuous Delivery führt.
      Vor der Livestellung eines Features sorgfältig zu testen ist in beiden Modellen erforderlich. Bei Feature-Branches erfolgt dieser Test aber nach Fertigstellung, während Feature-Toggles zumindest prinzipiell die Livestellung „unfertiger“ Features ermöglichen. Die Integration der einzelnen Commits erfolgt bei Branches also deutlich später, was zu größeren Änderungen in den Deployments führt, die dann aufwändiger zu testen sind (viele Änderungen erhöhen das Risiko, dass sich viele Fehler eingeschlichen haben).
      Toggles lassen sich auch in der Entwicklung mit Feature-Branches einsetzen: beispielsweise um Features „im Notfall“ zu deaktivieren, für A/B-Tests oder um ein Feature nach und nach auszurollen. Ganz bestimmt kann man auch Wege finden, Branches und Toggles zu kombinieren. Es sind halt Werkzeuge, die man bewusst einsetzen muss.

      Viele Grüße, Guido

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s

%d Bloggern gefällt das: