Continuous Integration & Delivery: Schrittmacher der Digitalisierung
Wie Softwareentwicklung die digitale Transformation befeuert
Sie ist Segen und Fluch zugleich: die digitale Transformation. Einerseits sorgt sie für mehr Effizienz in Produktions- und Geschäftsprozessen. Sie ebnet Unternehmen den Weg zu neuen Geschäftsmodellen und eröffnet bislang ungeahnte Marktpotenziale. Zugleich aber treibt die Digitalisierung alle vor sich her. Je mehr Unternehmen mit digitalen Effizienzsteigerungen punkten, desto stärker geraten jene unter Druck, die noch nicht so weit sind. Und je mehr digitale Giganten wie Google, Apple, eBay und Amazon die Erwartungen der Verbraucher mit softwaregetriebenen Neuerungen pushen, desto stärker sind alle anderen Mitspieler gezwungen, auf den Zug aufzuspringen.
Kurz: Wer die Bedürfnisse seiner Kunden schneller und genauer abdeckt als der Wettbewerb, hat die Nase vorn. Diese Dynamik, mit der sich Märkte und Bedürfnisse verändern, muss sich in der Softwareentwicklung spiegeln.
Agilität ist zwingend
Vor diesem Hintergrund ist der Bedarf nach agiler Softwareentwicklung entstanden. Es geht darum, dem Auftraggeber schnell und stetig Software zu liefern, die ihm so effizient wie möglich hilft, seine Aufgaben zu meistern.
Zu den besonders effizienten Entwicklungsmethoden, die in das schnelllebige Umfeld der Digitalisierung passen, gehören Continuous Integration, Delivery und Deployment. Zentrales Element dabei ist die weitgehende Automatisierung von Funktions- und Qualitätssicherungs-Tests – und zwar nicht erst, wenn ein umfangreiches Softwareprojekt abgeschlossen ist, sondern kontinuierlich bei jedem Entwicklungsschritt. Dadurch liegen eventuelle Fehlermeldungen schon nach wenigen Minuten oder Stunden vor, der Programmierer kann sie gegebenenfalls sofort beheben.
Unternehmen wie Google, Amazon, Netflix und andere setzen schon seit einiger Zeit auf diese Methoden. Sie sind in der Lage, ständige Anpassungen im Deployment- und Betriebsprozess vorzunehmen, weil sie ihre Entwicklung in kleinste Schritte unterteilen und zunehmend automatisieren. Genau das ist der Grundgedanke agiler Softwareentwicklung.
Kurze Sprints statt schwerfälliger Großprojekte
Die Zeiten monolithischer Softwareentwicklungen, Releasezyklen im Jahresrhythmus und langer Deployment-Downtimes sind jedenfalls vorbei. Heute sind kleine Bausteine und kurze Entwicklungs-Sprints gefragt. Große zeit-, risiko- und kostenintensive Softwareeinführungen mit einer Unzahl manueller Tests werden durch vollautomatisierte Lösungen ersetzt.
Die Intention hinter agilen Ansätzen wie Scrum ist es, die Entwicklung von Software effizienter zu machen. Die wesentlichen Pluspunkte sind:
- Ergebnisse sind schneller sichtbar.
- Der Kunde wird in den Entwicklungsprozess mit eingebunden.
- Sich verändernde Anforderungen werden in die Entwicklung schnell einbezogen.
Continuous Integration und Continuous Delivery helfen, die agile Entwicklung noch besser und konsequenter über den gesamten Prozess hinweg umzusetzen. Denn sie sparen Zeit und helfen, die Zielgenauigkeit und Qualität der Software zu steigern.
Im Umfeld klassischer Softwareentwicklung ist bislang folgender Ablauf typisch: Die Software ist ausgeliefert und installiert, der Kunde entdeckt einen Fehler – verursacht zum Beispiel durch einen Seiteneffekt als Folge eines Bugfix. Der Kunde nimmt Kontakt mit dem Support des Software-Lieferanten auf, der die Fehlermeldung an den Entwickler weiterleitet.
Das Problem ist offensichtlich: Wenn sich der Entwickler jetzt an die Fehleranalyse macht, muss er sich erst wieder in den Code eindenken. Den Fehler einzugrenzen und zu beheben ist in diesem Stadium vergleichsweise zeitaufwändig und teuer, da einfach zu viel Zeit seit der Entwicklung und Implementierung vergangen ist.
Nach dem Bugfix folgen Tests und Deployment – wiederkehrende manuelle Aufgaben, die in der heutigen Zeit zu lange dauern und zu teuer sind. Ganz zu schweigen davon, dass manuelles Deployment fehleranfällig ist. Code-Änderungen können Seiteneffekte erzeugen – siehe oben –, die in diesem Prozess oft unbemerkt bleiben.
Erster Schritt: Continuous Integration
Erste Abhilfe schafft die inzwischen relativ häufig eingesetzte Methode der Continuous Integration. Sie zeichnet sich durch automatisierte Integration aus. Der Vorteil: Bei den Modultests werden offensichtliche Fehler abgefangen, dadurch lassen sich die Schleifen zwischen Qualitätssicherung und Entwickler reduzieren. Das spart Kosten. Außerdem steigt durch ständige Regressionstests auf Modulebene die Qualität der Software.
Der nächste logische Schritt ist Continuous Delivery. Bis hierher werden mit Continuous Integration einzelne Module automatisch in die Software integriert. Ziel von Continuous Delivery hingegen ist es, tatsächlich lieferbare Softwarepakete, die sich auf jedem beliebigen System aufspielen lassen, automatisch zu bauen.
Entscheidender Erfolgsfaktor ist hier die Automatisierung vor allem der Tests. In der Praxis läuft das wie folgt: Sind die Features unter Mitwirkung der beteiligten Fachbereiche definiert und entwickelt, spielt der Entwickler seinen Code ins sogenannte Code-Repository ein – ein zentraler Server, auf dem der Programmcode liegt. Im Anschluss durchläuft der neu geschriebene Code die sogenannte Continuous Delivery-Pipeline mit einer Vielzahl automatisierter Tests, die natürlich zuvor geschrieben werden müssen.
Während der Code die Pipeline durchläuft, bekommt der Entwickler sofortige Rückmeldung. Das hat den Vorteil, dass er gedanklich noch im Thema ist, allein dadurch lassen sich Seiteneffekte vermeiden oder zumindest minimieren.
Die Pipeline
Die Ausprägung der Continuous Delivery-Pipeline ist abhängig vom jeweiligen Projekt und dessen spezifischen Anforderungen. Eine typische Pipeline kann folgende Funktionen enthalten:
- Das Projekt wird gebaut, dazu gehört zum Beispiel das Übersetzen des Quellcodes.
- In Unit-Tests wird die Software auf niedrigster Ebene in kleinsten Einheiten getestet.
- Statische Code Analyse: Sie umfasst das Testen auf Bugs und Verwundbarkeit (SQL-Injection), das eventuelle Missachten von Coding-Richtlinien oder ob die Komplexität zu hoch ist (Code-Smells). Auch Testabdeckung und redundante Codes werden hier erfasst.
- Automatisches Installieren der Applikation auf der Testumgebung.
- Integrationstests wie etwa der REST-Schnittstellen, Testen der Interaktion mit anderen Systemen wie Schnittstellen-Partner oder Datenbanken
- Akzeptanztests: Hier werden beispielsweise Use Cases im Browser getestet. Die Anforderungen etwa der Fachabteilung werden auf hohem Level geprüft: Verhält sich die Software wie erwartet beziehungsweise erwünscht?
- Optional beziehungsweise abhängig vom Projekt und dessen Anforderungen durchläuft die Software bestimmte Sicherheitstests – zum Beispiel mittels HP-Fortify oder OWASP-Scanner. Hier ist zu prüfen, ob diese Tests wirklich erforderlich und wirtschaftlich sinnvoll sind. Gegebenenfalls lassen sie sich auch durch manuelle Sicherheitstests ersetzen.
- In Lasttests wird geprüft, ob die Software sich unter Last anders verhält als gewünscht, und wenn ja, wie und warum. Lasttests sind überall dort zwingend, wo das Mengengerüst der Anforderung, für die die Software geschrieben wurde, eine Situation unter Last wahrscheinlich macht.
- Sind alle automatischen Tests erfolgreich durchlaufen, wird die Software auf der Approval-Umgebung installiert.
- Abschließend können manuelle Tests wie Usability-Tests oder Prüfungen durch die Fachabteilung durchgeführt werden. Usability-Tests lassen sich nicht automatisieren, da es hier um die Mensch-Maschine-Schnittstelle geht.
Entscheidend: die Unit-Tests
Es empfiehlt sich, den größten Aufwand und die größte Sorgfalt in die Unit-Tests (Punkt 2) zu stecken. Der Grund ist einfach: Je früher getestet wird und je kleiner die Units sind, desto schneller und zielgenauer ist das Feedback für den Entwickler. Alle nachfolgenden Tests sind wesentlich aufwändiger zu schreiben, dauern länger und sind fehleranfälliger, weil die getesteten Softwarepakete komplexer sind und mehr Abhängigkeiten bestehen. Funktioniert hier etwas nicht richtig, ist die Suche nach dem konkreten Bug wesentlich aufwändiger als bei kleinen Units.
Der Code durchläuft die Pipeline so oft, mit jeweiligen Rückmeldungen und Eingriffen des Programmierers, bis er sie ohne Fehlermeldung passiert. Jetzt kann die Software direkt automatisch geliefert werden. Auf diese Weise erreicht der Entwickler eine ständige Lieferfähigkeit der Software, wie sie mit einer manuellen Prozesskette nicht annähernd so effizient umsetzbar wäre.
Continuous Delivery integriert das automatisierte Testen als festen Bestandteil.
Übrigens: Falls doch mal ein Fehler in die Produktion gelangt – natürlich ist das auch bei dieser Methode nicht ganz auszuschließen –, sorgt eine umfangreiche Überwachung der Produktion für eine rasche Rückmeldung. Oft kann dadurch der Fehler behoben werden, noch ehe ihn der Kunde überhaupt entdeckt. Hinzu kommt, dass die Fehleranalyse durch das schnelle Feedback relativ günstig ist. Nicht zu vergessen: Die automatisierten Regressionstests verhindern Seiteneffekte, da ja auch für den Bug ein Test geschrieben wurde.
Bei herkömmlichen Softwareprojekten werden Tests meist erst am Ende eines Release oder allenfalls nach größeren Zwischenschritten eingeplant. Continuous Delivery dagegen integriert das automatisierte Testen als festen Bestandteil in die komplette Pipeline der Softwareentwicklung. Klar, dass sich die Time-to-Market dadurch enorm verkürzt.
Natürlich kann und soll auch bei Continuous Delivery nicht immer vollständig auf manuelle Tests verzichtet werden. Der entscheidende Vorteil aber ist, dass die Software bei den manuellen Tests schon einen so guten Stand hat, dass diese sehr effizient ablaufen können. Manuelle Tests können bei Bedarf mit automatisierten kombiniert werden. Mit kontinuierlichen Feedbackschleifen lässt sich dann der Automationsgrad sukzessive erhöhen, der manuelle Aufwand wird auf ein Minimum beschränkt.
Continuous Delivery spart Zeit und Kosten
Für den Entwickler macht Continuous Delivery die Arbeit wesentlich einfacher. Er muss nicht wochenlang warten, bis QS-Schleifen durchlaufen sind, sondern bekommt direktes Feedback vom Entwicklungssystem und kann dadurch Fehler viel schneller beheben. Schließlich ist er in der Regel noch im Code drin und muss sich nicht nach Wochen wieder neu eindenken.
Ein nicht zu unterschätzender Vorteil ist auch, dass das Projektrisiko sinkt, weil es immer einen funktionierenden Softwarestand gibt. Auch hier ist ein Blick in die Welt herkömmlicher Softwareentwicklung hilfreich: Bei umfangreichen Projekten sind Produktiv-Installationen bislang mit erheblichem Aufwand und hoher Komplexität verbunden. Basis ist eine sehr detaillierte Installationsanleitung.
Das Deployment selbst sollte durch Continuous Delivery "praktisch langweilig" werden.
Wird eine Fehlfunktion diagnostiziert, geht die Suche los. Liegt der Fehler in der Installationsanleitung oder in der Durchführung der Installation? Wenn das klar ist, stellt sich die Frage: Wo im komplexen Softwaregebilde ist der Bug? Nutzt man die Methoden der Continuous Integration & Delivery, wird die Installation programmiert und läuft auf Knopfdruck ab. Sie ist reproduzierbar, was die Fehlersuche erleichtert. Und Wissensmonopole werden abgebaut, weil die Installation auf der Basis von Software stattfindet und nicht auf der Basis des Wissens eines einzelnen Spezialisten.
Das Deployment selbst, für das früher enorm viel Zeit eingeplant wurde, sollte durch Continuous Delivery "praktisch langweilig" werden. Vor allem ist es mit Continuous Delivery möglich, einen neuen Softwarestand in kürzester Zeit zu deployen. Die ganze Arbeit wurde ja bereits im Vorfeld erledigt.
Damit geht die Installation einer neuen Softwareversion einfach, schnell und mit geringen Downtimes vonstatten. Oft sind Projekte, die früher zehn Personentage für das Deployment und dessen Vorbereitung gekostet hätten, innerhalb weniger Minuten installiert. Die gesamte Vorbereitung wird auf wenige Stunden reduziert. Allerdings darf man dabei nicht vergessen, dass ein Teil des eingesparten Deployment-Aufwands schon vorab in den Entwicklungsprozess eingeflossen ist.
Dennoch: Dass sich die Auftraggeber über schnelle Installation und kurze Downtimes freuen, versteht sich von selbst. Außerdem setzt mit der Zeit ein interessanter Zusatzeffekt ein: Die Bereitschaft, neue Anwendungen zu installieren und unter Marktbedingungen testen zu lassen, die zum Beispiel noch nicht alle geplanten Funktionen enthalten, steigt. Und genau solche Effekte bringen die digitale Transformation in Schwung.
Konsequenz vermeidet Komplexität
Natürlich wollen auch diese Methoden der Softwareentwicklung konsequent und kontrolliert angewandt werden. Ein bisschen Continuous Delivery ist wie ein bisschen Scrum. Wenn man die Vorteile wirklich will, muss man sich entscheiden.
Wer sich etwa an Continuous Integration auf Modulebene ergötzt und vergisst, auch die größeren Zusammenhänge in der Continuous Delivery-Pipeline automatisiert zu testen, läuft Gefahr, dann doch irgendwann den Überblick zu verlieren. Eine andere Problematik kann sich entwickeln, wenn die statische Code-Analyse oder gar die Unit-Tests vernachlässigt werden. Denn dann können auch gerne mal Funktionen mit 200 oder mehr Zeilen entstehen. Klassenlängen sind zu lang, oder es entstehen so viele Abhängigkeiten und Verschachtelungen, dass der rote Faden verloren geht.
Klar ist: Wer sich den hier beschriebenen Entwicklungsmethoden annähern will, darf den Initialaufwand nicht scheuen, der mit dem Aufsetzen der Pipeline und dem Erstellen von automatisierten Tests verbunden ist. Der lohnt sich aber spätestens, wenn eine Software länger eingesetzt werden soll. Und er macht sich bezahlt, wenn beispielsweise Change Requests anstehen. Hier wird allein dadurch Zeit und Geld gespart, dass weniger Fehler produziert werden.
Nicht zu vergessen: Sind die automatisierten Tests einmal aufgesetzt, lassen sie sich immer wieder einsetzen. Manuelle Tests hingegen kosten Zeit, sind nicht reproduzierbar und vergleichsweise teuer.
Zielführend auch in klassischer Umgebung
Continuous Delivery beschränkt sich übrigens nicht nur auf agile Projekte. Die Methode ist auch in klassischen Softwareprojekten durchaus zielführend. Hier kann sie vor allem dazu dienen, innerhalb des Entwicklungsteams effizienter zu werden. In agilen Projekten allerdings ist es geradezu unverzichtbar, einen Continuous Delivery-Prozess aufzusetzen, schließlich muss hier ständig Software geliefert werden.
Wie bei jeder Methode jedoch gilt es im Einzelfall abzuwägen, ob sie sinnvoll ist. Bei Miniprojekten etwa oder einem Showcase, der nicht weiterentwickelt wird, kann der Initialaufwand zu hoch sein und die Methode kann ihre Vorteile nicht ausspielen. Bei Softwarelösungen allerdings, die längere Zeit laufen sollen, ist der Einsatz von Continuous Delivery durchaus sinnvoll. Dies umso mehr, wenn absehbar ist, dass die Software im Lauf der Zeit weiterentwickelt werden soll. Oder wenn sie schnell an veränderte Anforderungen angepasst werden muss.
Nicht erst seit IoT und Big Data ist klar: die Digitalisierung und die Vernetzung macht die Welt komplexer. Diese Komplexität lässt sich nur noch beherrschen, wenn automatisierte Unit-, Integrations-, Funktions- und Qualitätstests zum Standard werden. Wenn wir in der Softwareentwicklung weitermachen wie bisher, bricht das Kartenhaus irgendwann zusammen.
Wer die Wettbewerbsvorteile ausschöpfen will, die in der Digitalisierung stecken, muss vorne dabei sein und seine Softwareentwicklung automatisieren. Nicht mit der Brechstange, sondern Schritt für Schritt.