Superstarke Continuous Delivery mit Git
Jetzt, da Git das mühevolle Mergen erleichtert, werden Branching-Workflows sehr viel attraktiver.
Sarah Goff-Dupont
Principal Writer
Wir alle kennen den Ausspruch: "Vorsicht bei Code, den nur eine Person geschrieben hat." Genauso kennen wir die Vorteile von Teamwork bei der Softwareentwicklung: verschiedene Denkweisen, unterschiedliche Hintergründe und Erfahrungen ... und wenn du diese Unterschiede bei der Lösung von Problemen mit einbringst, hast du am Ende eine bessere Software. Sie ist einfacher zu verwalten, qualitativ hochwertiger und für die Benutzer letztendlich nützlicher.
Aber genauso wissen wir: Die Entwicklung im Team kann chaotisch sein.
Du versuchst zu verstehen, wer an welchem Codeabschnitt arbeitet, möchtest sicherstellen, dass Änderungen keinen Konflikt auslösen, bist bemüht, Fehler zu finden, bevor es die Kunden tun, und hast es dir zur Aufgabe gemacht, alle Projektbeteiligten stets auf dem Laufenden zu halten. Wie sich herausstellt, kann das Git-Branching oder die Continuous Delivery jedes dieser Probleme lösen.
Ich möchte dich gerne davon überzeugen, dass die Kombination aus beiden (vielleicht gemixt mit ein paar anderen Kick-Ass-Tools, nur zum Spaß) dein Zaubertrank-Rezept zum Erfolg ist.
Die Leistungsfähigkeit von Branch-basierten Workflows
Ehrlich gesagt ist Git an und für sich gar nicht so perfekt für die Continuous Delivery (CD). Aber Branching-Workflows sind ideal für CD und Git ist ideal für Branching-Workflows. Ein Branch-and-Merge-Workflow ist nicht nur der ideale Partner der CD – du kannst mit ihm auch lästige Fehler beheben, neue Technologien ausprobieren oder einfach eine neue Funktion von Grund auf neu programmieren, ganz ohne Risiko, dass deine Änderungen deinen Teamkollegen bei ihren eigenen Tasks in die Quere kommen.
Klar, Branches kannst du auch mit Subversion und anderen herkömmlichen Versionskontrollsystemen erstellen. Aber machen wir doch einen kurzen Exkurs und lernen wir den bösen Zwilling von Branching kennen: den Merge.
Herkömmliche Versionskontrollsysteme wie Subversion sind einfach nicht so gut beim Nachverfolgen von Dateiversionen in verschiedenen Branches. Und wenn es Zeit für den Merge ist, muss Subversion sehr oft anhalten und nach dem Weg fragen. (Du weißt schon, dieses kleine Pop-up mit der Frage "Möchtest du diese oder jene Zeile in der Merge-Version?") Da beim Durchführen von Merges so viel menschliche Interaktion nötig ist, setzen Teams gerne Code-Freezes ein, damit die Person, die den Merge gerade durchführt, nicht von den Änderungen in einem der Branches unterbrochen wird. Code-Freezes kosten Zeit – und Zeit ist Geld.
Git dagegen ist wirklich gut darin, Änderungen an verschiedenen Dateiversionen in verschiedenen Branches nachzuverfolgen, und weiß immer, wie der gemeinsame Vorgänger dieser Datei aussah. Es hat quasi ein eingebautes GPS, mit dem es Merges durchführen kann, ohne ständig anzuhalten und dich nach dem Weg zu fragen.
Mit Git hast du die Freiheit, die Leistungsfähigkeit von Branching auf eine Art und Weise zu nutzen, die mit Subversion nicht umsetzbar wäre. Der geringe Aufwand für das Branching und Mergen macht Branches, die nur einen oder zwei Tage benötigt werden, nicht nur realisierbar, sondern auch vorteilhaft.
Okay, gut. Aber warum genau ist Branching überhaupt so gut für Continuous Delivery geeignet?
Branches halten den Main-Branch sauber und Release-bereit
Wir haben bereits festgestellt, dass kurzlebige Branches eine gute Möglichkeit für Entwickler sind, an einem Projekt oder einer Funktion zusammenzuarbeiten, ohne sich gegenseitig auf die Füße zu treten. Aber noch wichtiger für CD ist, dass das Isolieren laufender Arbeiten in Entwicklungs-Branches die Main- sowie die stabilen Versions-Branches sauber hält. So kannst du sie ausliefern, wann du möchtest.
Das bedeutet, du solltest alle deine automatisierten Tests über Entwicklungs-Branches ausführen. Entwickler erhalten eindeutige Signale bezüglich der Qualität ihres Codes und können dann zuversichtlich entscheiden, wann der Merge für ihre Änderungen durchgeführt wird. (Wenn du bei den automatisierten Tests noch nicht ganz durchsteigst, dann schau dir diesen Beitrag von RebelLabs an. Dort findest du eine lockere Einführung und Rezepte dafür, wie du deine ersten Unit-Tests schreibst.)
Es bedeutet auch, Pull-Requests von Git als eine Art Code-Review zu nutzen, damit sich dein gesamtes Team auf die Wartungsfreundlichkeit des Codes und die Interoperabilität mit anderen Bereichen der Codebasis verlassen kann. Ja, das ist mehr Arbeit im Vorfeld als bei herkömmlichen Bereitstellungsmodellen. Und ja, es lohnt sich.
Lösung anzeigen
Hochwertige Software entwickeln und ausführen mit Open DevOps
Zugehöriges Material
Was ist die DevOps-Pipeline?
Erfolgreiche Continuous Delivery ist davon abhängig, dass du deine Release-Branches sauber hältst.
Als Beispiel: Bei Atlassian gibt es zwischen allen Entwicklungsteams die Vereinbarung, dass niemals etwas direkt auf den Main- oder den stabilen Branches committet wird. Alle arbeiten an Branches. Tatsächlich haben wir ein so gutes Gefühl beim Branching, dass wir für jeden Jira-Vorgang, den wir angehen, einen separaten Branch erstellt haben – mehr dazu in Kürze.
Die Nutzer können also so viele Tests kaputt machen und in ihren Branches so viel Schaden anrichten, wie sie möchten! Der Main-Branch bleibt in einem Release-bereiten Zustand, wo du neue Branches ganz ohne vererbten, fehlerhaften Code erstellen kannst. Das ist ein Vorteil für CD und die allgemeine Entwicklerproduktivität (ganz zu schweigen von der Moral).
Branches helfen dir dabei, Beiträge von außerhalb des Teams anzunehmen
Da in Git Branching möglich ist – und insbesondere auch das Abspalten ganzer Repositorys – wird es einfach, Beiträge von Personen außerhalb des unmittelbaren Teams anzunehmen: von Auftragnehmern, Entwicklern aus Partnerunternehmen, Entwicklern aus anderen Geschäftsbereichen usw. Du musst dir nicht mehr den Kopf darüber zerbrechen, dass andere, die mit deiner Codebasis nicht vertraut sind, einfach so Änderungen an wichtigen Branches vornehmen und dadurch verhindern, dass du neuen Code ausliefern kannst.
Gründliches, automatisiertes Testen der von ihnen erstellten Branches oder abgespaltenen Repositorys ist auch hier wieder der Schlüssel zu gelungener Zusammenarbeit. Du solltest ihre Builds und Testergebnisse überprüfen, bevor du Merges in deiner Hauptcodezeile genehmigst.
Korrektes Branching = Übersichtliche Projektverfolgung
Der aktuelle Trend: Erstelle einen Entwicklungs-Branch für jede Story, jeden Bugfix oder jede Task (d. h. jeden Jira-Vorgang), die du ausführst. Bei Atlassian haben wir dieses Branch-pro-Vorgang-Modell vor einigen Jahren eingeführt und wir haben es nicht bereut! Es erfreut sich auch bei unseren Kunden großer Beliebtheit.
Einen Branch für jeden Vorgang zu erstellen macht es einfach, die Änderungen auszuwählen, die zur Produktion ausgeliefert oder in ein Release-Bundle gepackt werden sollen. Da du auf dem Main-Branch nicht massig Änderungen anhäufst, kannst du auswählen, was in den Main-Branch kommt und was nicht. Du kannst das MVP (Minimum Viable Product) eines Epics plus ein nettes Extra ausliefern, anstatt zu warten, bis alle Extras fertig sind. Oder du lieferst einen einzigen Bugfix aus, und das im Rahmen eines regulären Releases. Selbst wenn der Fix dringend ist, musst du dich nicht mit dem Zurücksetzen anderer Änderungen stressen, die noch nicht bereit zur Auslieferung sind, nur um diese eine Änderung herauszugeben.
Und diese bequeme Auslieferung einer einzigen Codeänderung ist die Quintessenz der Continuous Delivery.
Dieser Ansatz hält nicht nur ungeprüften Code vom Main-Branch fern. Wenn der Name des Branches den entsprechenden Jira-Vorgangsschlüssel und den Namen oder die Initialen des Entwicklers enthält, ist der Entwicklungsstand von jedem aktuell bearbeiteten Vorgang absolut eindeutig.
Beachte die im obigen Bild verwendete Namenskonvention: der eindeutige Schlüssel für den ausgeführten Jira-Vorgang plus eine kurze, für Menschen lesbare Beschreibung, worum es bei diesem Vorgang geht. Als Release-Manager oder Stakeholder kannst du beim Betrachten des oben gezeigten Repositorys auf den ersten Blick erkennen, dass die User Story, verfolgt von AMKT-13952, bereit für den Release ist, da du siehst, dass der Merge zum Main hier bereits durchgeführt wurde. Das ist Nachvollziehbarkeit ohne den ganzen manuellen Aufwand.
Also wie funktioniert der Workflow mit Git + Continuous Delivery?
Gut, dass du fragst! Ich werde hier nur kurz darauf eingehen, denn in anderen Artikeln auf dieser Seite werden die einzelnen Phasen ausführlicher beschrieben.
- Erstelle einen Branch für jeden Vorgang, an dem du arbeiten möchtest. Füge den Jira-Vorgangsschlüssel in den Namen des Branches ein, damit klar ist, wofür der Branch gedacht ist. Und wenn du andere Atlassian-Tools wie Bitbucket oder Bamboo verwendest, werden sie diesen Vorgangsschlüssel aufgreifen und Verknüpfungen zwischen dem Vorgang, deinem Branch, all deinen Commits, deinen Builds, deinen Pull-Requests und deinen Bereitstellungen erstellen, die mit diesem Vorgang zusammenhängen. Anders ausgedrückt: Vorgangschlüssel sind fantastisch.
- Nimm Änderungen an den Branches vor. Du bist hier in deiner eigenen kleinen Welt, also tobe dich aus. Probiere Neues aus. Mach Dinge kaputt. Es spielt keine Rolle, denn du wirst auch ...
- Deinen Branch unter CI stellen. Du und dein Team entscheiden, ob hier spezielle Tests wie Belastungstests oder UI-basierte End-to-End-Tests durchgeführt werden, und ob jedes Mal, wenn Änderungen in deinen Branch gepusht werden, automatisch ein Testlauf durchgeführt wird. Die Teams von Atlassian führen in der Regel Unit- und Integrationstests in den Entwicklungsbranches durch.
- Aktualisiere deinen Branch regelmäßig mit der neuesten Version des Main-Branch. Du kannst dafür "rebase" oder "branch-commit" verwenden. Es liegt ganz bei dir! (Aber denk daran, einen Branch, den du mit anderen Entwicklern teilst, nicht zu rebasen – davon kriegen sie schlechte Laune.) So oder so, du wirst vor dem Mergen Integrationskonflikte finden, was dir wiederum hilft, den Main-Branch sauber zu halten.
- Erstelle einen Pull-Request, wenn du bereit für den Merge bist. Das bedeutet, die Implementierung ist abgeschlossen, du hast Änderungen von deinen Teamkollegen miteinbezogen sowie alle entstandenen Konflikte gelöst und dein Branch besteht alle Tests.
- Führe den Merge durch und stelle nach Belieben bereit. Einige Teams ziehen es vor, jede Änderung automatisch auszuliefern, sobald der Merge mit dem Main-Branch durchgeführt wurde und alle Tests dort bestanden wurden – das Modell von Continuous Deployment. Andere Teams ziehen es vor, selbst zu entscheiden, welche Änderungen wann ausgeliefert werden sollen. Das liegt ganz an dir und deinem Team.
Fazit
Also: Branching-Workflows machen Continuous Delivery einfacher und Git macht Branching unkomplizierter. Lies weiter, um mehr darüber zu erfahren, wie du dein Git-Repository CD-freundlich einrichtest und all diese Ideen mithilfe der Tools von Atlassian in die Praxis umsetzen kannst. Wir sehen uns auf der nächsten Seite!
Diesen Artikel teilen
Nächstes Thema
Lesenswert
Füge diese Ressourcen deinen Lesezeichen hinzu, um mehr über DevOps-Teams und fortlaufende Updates zu DevOps bei Atlassian zu erfahren.