Continuous Integration

Steigere mit schnellerem Feedback die Agilität deines Teams. Weil du nicht schneller sein kannst als deine Tests.

Dan Radigan Dan Radigan

Nichts unterstützt – oder untergräbt – Agilität mehr als die Verpflichtung eines Teams zu Continuous Integration (CI). Das mag sich unheilvoll anhören (vor allem wenn dein Team CI noch nicht einsetzt), aber es gibt auch gute Neuigkeiten. Ganz gleich, welche Technologien ein Team einsetzt, ist sehr wahrscheinlich ein Framework für Continuous Integration und automatisierte Tests verfügbar, das für die jeweilige Codebasis funktioniert.

Was ist Continuous Integration?

Continuous Integration ist die routinemäßige Integration von Code-Änderungen in den Haupt-Branch eines Repositorys sowie das Testen von Änderungen so früh und so häufig wie möglich. Im Idealfall integrieren die Entwickler ihren Code jeden Tag, wenn nicht sogar mehrmals täglich.

Vorteile der Continuous Integration

Eine Investition in CI ermöglicht schnelle Feedbacks zu Codeänderungen. Und schnell heißt in diesem Fall "innerhalb von Minuten". Ein Team, das hauptsächlich manuelle Tests einsetzt, erhält möglicherweise innerhalb einiger Stunden Feedback, aber in der Realität kommt das Feedback nach umfassenden Tests erst einen Tag – oder mehrere Tage – nach der Codeänderung. Weil bis dahin weitere Änderungen durchgeführt wurden, wird die Fehlerbehebung zu einer archäologischen Expedition, da sich Entwickler erst durch mehrere Schichten Code graben müssen, um an die Ursache des Problems zu gelangen.

Das ist definitiv nicht schnell.

Gesicherte Qualität durch Continuous Builds und automatisierte Tests

Wie viele von uns haben schon den neuesten Quellcode heruntergeladen und festgestellt, dass er nicht kompiliert werden kann oder einen schwerwiegenden Fehler enthält? Das ist der Tod der Produktivität!

Es gibt zwei Verfahrensweisen, um diese Situation zu vermeiden:

Continuous Builds: Das Projekt wird aufgebaut, sobald die Änderung erfolgt ist. Idealerweise ist das Delta zwischen jedem Build ein einziger Änderungssatz.

Testautomatisierung: Die Software wird programmgesteuert überprüft, um die Qualität zu sichern. Tests können Aktionen in der Software über die Benutzeroberfläche (mehr dazu gleich) oder aus der Backend-Serviceschicht initiieren.

Stell dir diese zwei Verfahrensweisen wie Erdnussbutter und Marmelade vor: Beides schmeckt allein schon gut, ist aber zusammen unschlagbar! Bei Continuous Integration werden Continuous Builds mit einer Testautomatisierung kombiniert, um sicherzustellen, dass jeder Build auch die Qualität der Codebasis auswertet.

Und vergiss nicht: Um die Vorteile voll auszuschöpfen, muss ein Team auch über die Disziplin verfügen, die Entwicklung zu unterbrechen und Probleme sofort zu beheben. Die Energie, die ein Team in das Schreiben von Tests und das Konfigurieren der Automatisierung investiert (und glaube mir, das ist eine Investition), ist vollkommen vergebens, wenn nicht funktionierende Builds zugelassen werden. Das Schützen der CI-Investition und das Schützen der Qualität der Codebasis sind im Wesentlichen identisch. 

Testverfahren bei Continuous Integration: Unit-Tests, API-Tests und funktionale Tests

CI wird in zwei Hauptphasen durchgeführt. Im ersten Schritt wird sichergestellt, dass der Code kompiliert werden kann. (Oder bei interpretierten Sprachen werden einfach alle Teile zusammengezogen.) Im zweiten Schritt wird sichergestellt, dass der Code gemäß dem Design funktioniert. Die sicherste Methode dafür ist eine Reihe von automatisierten Tests, die alle Ebenen des Produkts überprüfen. 

Unit-Tests

Einheitentests werden sehr nah an den Kernkomponenten im Code ausgeführt. Sie sind die erste Maßnahme für eine Sicherung der Qualität.

Vorteile: Einfach zu schreiben, schnelle Ausführung, enge Modellierung der Architektur der Codebasis

Nachteile: Unit-Tests überprüfen nur die Kernkomponenten der Software. Sie spiegeln keine Benutzer-Workflows wider, die oft die Zusammenarbeit zwischen mehreren Komponenten beinhalten.

Da ein Einheitentest aufzeigt, wie der Code funktionieren sollte, können sich Entwickler mithilfe von Einheitentests über den aktuellen Stand dieses Codebereichs informieren.

API-Tests

Gute Software ist modular, was eine klarere Trennung der Arbeiten über mehrere Anwendungen hinweg ermöglicht. APIs sind die Endpunkte, an denen verschiedene Module miteinander kommunizieren. API-Tests überprüfen diese, indem sie Aufrufe von einem Modul zum anderen ausführen.

Vorteile: Im Allgemeinen einfach zu schreiben, schnelle Ausführung und einfache Modellierung der Interaktion von Anwendungen

Nachteile: In einfachen Bereichen des Codes können API-Tests einige Unit-Tests imitieren.

Da APIs die Schnittstellen zwischen Teilen der Anwendung sind, sind sie besonders nützlich bei der Vorbereitung auf ein Release. Sobald ein Build eines Release-Kandidaten alle API-Tests bestanden hat, kann das Team diesen viel zuversichtlicher an Kunden ausliefern. 

Funktionstests

In funktionalen Tests werden größere Bereiche der Codebasis bearbeitet und Benutzer-Workflows modelliert. In Webanwendungen interagieren beispielsweise HTTPUnit und Selenium direkt mit der Benutzeroberfläche, um das Produkt zu testen.

Vorteile: Bugs werden sicherer gefunden, weil Benutzeraktionen imitiert werden und die Interoperabilität mehrerer Komponenten getestet wird.

Nachteile: Diese Tests sind langsamer als Unit-Tests und manchmal werden aufgrund von Netzwerklatenzen oder eines vorübergehenden Ausfalls an einer anderen Stelle im Technologie-Stack falsch negative Ergebnisse gemeldet.

Teams stellen oft fest, dass die Ausführungsgeschwindigkeit der automatisierten Tests nachlässt, je näher sie dem tatsächlichen Benutzer-Workflow kommen. HTTPUnit ist schneller, da es sich nicht um einen Webbrowser mit vollem Funktionsumfang handelt. Selenium kann nur so schnell wie der Webbrowser ausgeführt werden, bietet aber den Vorteil, gleichzeitig über mehrere Webbrowser ausgeführt werden zu können. Trotz dieser Vorbehalte sind funktionale Tests höchst wertvoll und stellen viel schneller Feedback bereit, als menschliche Tester es könnten.

Wo wir gerade beim Thema sind ...

Einige Tester sehen automatisierte Tests als existenzielle Bedrohung an. Diese Denkweise greift zu kurz und könnte nicht weiter von der Wahrheit entfernt liegen. Tester werden von der Schinderei wiederholter Testaufgaben befreit und können Zeit mit Risikoanalysen, Testplanung und dem Ausbau anderer Kompetenzen verbringen – z. B. das Programmieren lernen!

Für eine schnelle Continuous Integration sorgen

Bei Atlassian möchten wir, dass Entwickler Innovationen vorantreiben und unsere Codebasis ordentlich bleibt. Wir legen großen Wert darauf, die "innere Feedback-Schleife" des Entwicklers zu verkürzen – d. h. die Zeit, die erforderlich ist, um Änderungen aufzubauen und Testergebnisse zu erhalten.

Die Ausführung automatisierter Tests kann sich schnell summieren und die Build-Dauer verlängern. Eine Strategie besteht darin, automatisierte Tests parallel auf mehreren Servern oder "Build-Agents" auszuführen, damit der CI-Server tatsächlich 2, 20 oder sogar 200 Tests gleichzeitig ausführt. Bei Cloud-Technologien kann die CPU-Leistung leicht skaliert werden, um die Anforderungen des Entwicklerteams zu erfüllen, wenn die Test-Suite wächst. Aber die CPU-Leistung ist nicht unbegrenzt. Teste jeden Bereich des Codes vollständig, aber nicht wiederholt. Redundante Tests verlängern die Build-Dauer (und verschwenden CPU-Leistung). Je schneller Entwickler grünes Licht bekommen, umso schneller können sie mit dem nächsten Element im Backlog fortfahren.

Branching und CI: ein himmlisches Paar!

Viele Teams vermeiden das Branching wegen problematischer Merges. Aber mit neueren Technologien in der Versionskontrolle wie Git wurde sowohl das Branching als auch das Mergen vereinfacht. Um sicherzustellen, dass der Hauptentwicklungszweig ("Master" im Git-Jargon) integer bleibt, solltest du denselben Grad der Continuous Integration auf allen Entwicklungs- und stabilen Versions-Branches ausführen. Wenn der Build auf einem Branch durchgeht, kann das Team zuversichtlich sein, dass dieser Code in den Upstream gemergt werden kann.

Mit Branching, Continuous Integration und Testautomatisierung können Teams produktiv und innovativ sein, aber dennoch die Codequalität schützen. Wenn du bereit für die nächsten Schritte bist, dann lies dir unsere Schritt-für-Schritt-Anleitung für den Einstieg in CI durch.

Das ist agile Entwicklung in Hochform: die regelmäßige Bereitstellung funktionierender Software mit minimalen technischen Schulden ohne Beeinträchtigung der Genialität.