Man kennt das Sprichwort: „Obacht vor Code, der nur von einer Person geschrieben wurde“, und man kennt die Vorteile davon, Software im Team zu erstellen. Unterschiedliche Denkweisen, unterschiedliche Hintergründe und Erfahrungen. Und sobald man diese Unterschiede auf ein zu lösendes Problem loslässt, entsteht als Resultat bessere Software mit besserer Wartbarkeit, höherer Qualität und echtem Mehrwert für den Endanwender. Aber da gibt es noch eine Sache, die allen bewusst ist: Entwicklung im Team kann ganz schön chaotisch werden.

Alle versuchen zu verstehen, wer an welchem Teil des Codes arbeitet, alle sind damit beschäftigt, sicherzustellen, dass Änderungen keine Konflikte auslösen und Defekte zu finden und zu beheben, bevor Kunden sie entdecken. Obendrein müssen alle über den Projektfortschritt auf dem Laufenden gehalten werden. Jedes dieser Probleme wird entweder durch Branching in Git oder dem Einsatz von Continuous Delivery gelöst. Die Kombination aus beidem – ergänzt durch einige Werkzeuge – ergeben einen Hochgeschwindigkeitsmix für den Erfolg. Warum das so ist, wird dieser Artikel zeigen.

Die Überlegenheit von Git Workflows für Continuous Delivery nutzen

Nüchtern betrachtet liegt es nicht an Git selbst, dass es sich so gut für Continuous Delivery eignet. Vielmehr sind es die Branching Workflows, die perfekt für den Gedanken hinter Continuous Delivery geeignet sind, und Git ist dank der guten Unterstützung für viele Zweige wunderbar geeignet für diese Branching Workflows.

Ein weiterer Vorteil von Branch-And-Merge-Workflows ist das einfache Ausprobieren neuer Technologien, sinnvolles Beheben lästiger Bugs oder der Implementierung eines neuen Features. Und das alles, ohne zu riskieren, dass die eigenen Änderungen andere Team-Mitglieder daran hindern, selbst am Code weiterzuarbeiten.

cdw-1

Selbstverständlich lassen sich auch mit Subversion und anderen, klassischen Versionskontrollsystemen Zweige erstellen. Aber der größte Feind eines jeden Branches ist der Merge.

Klassische Versionskontrollsysteme wie Subversion sind einfach nicht besonders gut darin, verschiedene Versionen von Dateien in unterschiedlichen Zweigen zu verfolgen. Kommt es zur Zusammenführung zweier Versionen der selben Datei, dem Merge, dann muss in Subversion viel händische Arbeit verrichtet werden. Sie kennen das Popup: „Möchten Sie Zeile aus A, oder diese Zeile aus B, oder diese… im Merge-File haben?“. Die Tatsache, dass so viel menschliches Eingreifen für Merges notwendig ist, hat zu Konstrukten wie dem „Code Freeze“ geführt. Code Freeze bedeutet, niemand darf am Code weiterarbeiten bis der Merge durchgeführt ist – sodass dieser nicht durch neue Änderungen gestört wird. Code Freezes sind teuer: Es ist unproduktive Zeit für alle Entwickler, deren Hände gebunden sind, während sie auf den Merge warten.

Git ist auf der anderen Seite gut darin, Änderungen an Dateien über verschiedene Zweige hinweg zu verfolgen und ist immer darüber auf dem Laufenden, wie die gemeinsame Ursprungsdatei aussah. Man kann sich dies als ein eingebautes GPS vorstellen, welches dabei hilft, sich durch Merges zu hangeln – ohne ständig nach der Richtung zu fragen.

Mit Git fällt es viel leichter, die Vorzüge von Branching auszuspielen, die in anderen Versionskontrollsystemen wie Subversion eher unpraktisch wären. Der Overhead durch Branching und Merging ist so gering, dass Zweige, die lediglich einen Tag oder gar nur ein paar Stunden existieren, nicht nur machbar, sondern sinnvoll werden.

Aber was macht Zweige so sinnvoll für Continuous Delivery?

Branches halten den Hauptzweig sauber und veröffentlichbar

Wir wissen soweit, dass kurzlebige Zweige ein probater Weg für Entwickler sind, einfach und schnell zusammen an neuen Projekten oder Features zu arbeiten, ohne sich gegenseitig zu behindern. Viel wichtiger für Continuous Delivery ist aber die Tatsache, dass die Isolation der Entwicklungsarbeit den Hauptzweig und stabile Versionszweige in einem sauberen Zustand hält, sodass diese zu jeder Zeit ausgeliefert werden können.

So ist es ist jederzeit möglich, die ganze Palette an automatisierten Tests auf die Entwicklungszweige loszulassen und Entwicklern damit eindeutiges Feedback zur Qualität ihres Codes zu geben. Weiterhin geben diese Informationen zusätzliches Vertrauen, wann welche Änderungen bereit dazu sind, in einen stabilen Zweig integriert zu werden.

Das bedeutet auch, dass Pull Requests als eine Art Code Review eingesetzt werden, um dem gesamten Team mehr Transparenz und Vertrauen bezüglich der Wartbarkeit und Kompatibilität des entwickelten Codes zu geben. Zwar bedeutet dies mehr Vorarbeit als klassische Auslieferungsmodelle, es ist den zusätzlichen Aufwand aber mehr als wert.

Erfolgreich umgesetzte Continuous Delivery basiert darin, die Release-Zweige blitzsauber zu halten.

Ein Beispiel aus der Welt von Atlassian: Alle Entwicklerteams bei Atlassian haben die Vereinbarung getroffen, dass niemals etwas direkt in den master-Zweig oder andere stabile Zweige committet wird. Alle Arbeiten werden mithilfe von Zweigen durchgeführt. Atlassian setzt sogar so sehr auf Zweige, dass für jedes JIRA-Issue, an dem gearbeitet wird, ein neuer Branch erstellt wird. Das bedeutet, dass Beteiligte so viele Tests zum fehlschlagen bringen und den Code in den Zweigen so sehr zerpflücken können, wie sie möchten. Der Master-Zweig bleibt stabil, und Atlassian bleibt in der Lage eine Veröffentlichung davon durchzuführen – ohne auf einem Haufen kaputtem Code zu sitzen. Das erhöht die Produktivität ungemein.

Zweige helfen dabei, Einbringungen von außen zu fördern

Die Branching-Funktionalität von Git und die Fähigkeit, Kopien von ganzen Repositories anzulegen, macht es einfach, Einbringungen von außerhalb des Kernteams in Form von Code zu akzeptieren. Externe Mitarbeiter, Entwickler von Partnerfirmen oder Entwickler anderer Abteilungen können einfach neuen Code oder Verbesserungen einreichen. Man muss sich nicht darum sorgen, dass sich Personen, die sich nicht mit der Codebasis auskennen, irgendetwas kaputt machen könnten.

Und wieder führt rigoroses automatisiertes Testen aller Zweige und aller abgezweigten Repository-Kopien zu glücklicher Zusammenarbeit. Einbringungen von Extern sollten stets auf Basis der Build-Resultate und mithilfe von Code Review geprüft werden, bevor die Änderungen in den master-Zweig integriert werden.

Tipp vom Experten
Repository-Manager wie Bitbucket unterstützen Git Hooks, mit deren Einsatz Qualitätsstandards durchgesetzt werden können. So kann beispielsweise eine Regel gesetzt werden, dass der Build eines Zweigs zuerst erfolgreich durchgelaufen sein muss, bevor dieser akzeptiert und gemergt werden kann.

Richtiges Branching führt zu mehr Durchblick im Projekt

Zum guten Ton gehört heutzutage, einen Entwicklungszweig pro Story oder Bug-Fix (d.h. jedes JIRA-Issue) anzulegen. Atlassian hat dieses Branch-per-Issue-Schema seit einigen Jahren im Einsatz und ist immer noch voll davon überzeugt. Die Australier berichten auch von Kunden, die dieses Schema begeistert einsetzen.

Erstellt man einen Zweig für jeden Vorgang, wird es kinderleicht, händisch diejenigen Änderungen zu selektieren, die aufs Produktivsystem oder als Release veröffentlicht werden sollen. Man ist nicht länger dabei, Berge von Änderungen im master-Zweig anzuhäufen, sondern geht viel selektiver vor und bestimmt, was wann in den master-Zweig kommt und was nicht. So ist man in der Lage, den MVP eines Epics und ein Nice-to-Have auszuliefern, ohne darauf warten zu müssen, dass alle Nice-to-Haves vorliegen. Oder man liefert einen einzigen Bugfix aus, eingebettet in ein reguläres Releases. Selbst wenn der Fix dringend ist, muss man sich nicht damit herumschlagen, aus Änderungen, die bereit zur Veröffentlichung sind, und denjenigen, die es nicht sind, zu wählen. Hier bekommt man einfach nur die Korrektur schnellstmöglich an den Kunden. Und genau diese Einfachheit der Auslieferung ist die Essenz von Continuous Delivery.

cdw-2

So sorgt dieser Ansatz nicht nur dafür, dass nicht geprüfter Code dem master-Zweig fernbleibt, sondern auch für einen kristallklaren Durchblick zum Fortschritt eines jeden Vorgangs, sofern man den JIRA Issue-Key und die Initialien des zuständigen Entwicklers in den Branchnamen aufnimmt.

Wie funktioniert der Continuous Delivery Git-Workflow genau?

Gute Frage – dieser Abschnitt verhilft hoffentlich zu mehr Klarheit. Im Rahmen dieses Artikels reicht es nur für eine kurze High-Level-Übersicht. Für mehr Details besuchen Sie am besten unsere Lösungsseiten oder die Continuous Delivery Microsite von Atlassian. Doch nun zum Vorgehen:

  • Man erstelle einen Zweig für den aktuellen Vorgang, an dem man arbeiten möchte. Dabei den JIRA Issue Key im Namen des Branches festhalten, sodass klar ist, wofür dieser Zweig gedacht ist. Falls Sie Atlassian-Werkzeuge wie Bitbucket oder Bamboo einsetzen, werden der Issue-Key und Issue-Links automatisch gesetzt, sodass der Vorgang, der Zweig, alle Commits, Builds, Pull Requests und Deployments miteinander verknüpft und historisiert werden. Kurzum: Issue-Keys sind magisch.
  • Man mache Änderungen am Code im Zweig. Hier haben Sie freie Hand. Probieren Sie Neues aus, machen Sie etwas kaputt. Alles ist relativ, denn…
  • Man versorge den Zweig mit Continuous Integration. (Bamboo tut dies übrigens vollautomatisch). Es liegt an Ihnen und Ihrem Team zu entscheiden, ob spezielle Tests wie Belastungstest oder UI-Tests ausgeführt werden und ob diese Tests automatisch via Build-Trigger bei jeder Änderung am Zweig ausgeführt werden. Bei Atlassian lassen die Teams in der Regel Unit- und Integrationstests auf Entwicklungszweigen laufen und lassen die Entwickler entscheiden, wie oft diese Tests ausgeführt werden, um Build-Ressourcen zu sparen und kurze Wartezeiten zu garantieren.
  • Man halte den Zweig stets mit den neusten Änderungen aus master aktuell. Man kann entweder Rebasing oder Branch-Commits dafür verwenden. Das liegt an Ihnen, aber behalten Sie im Hinterkopf, dass man bei Rebasing aufpassen sollte. Rebasing bei einem von mehreren Entwicklern genutzten Zweig sollte stets mit allen Beteiligten abgesprochen werden, um Unmut zu vermeiden. Egal wie Sie vorgehen, Merge-Konflikte werden somit stets vor der Rück-Integration nach master bereits entdeckt und behoben – die Zauberformel für einen sauberen master-Zweig.
  • Man erstelle einen Pull Request, wenn die Änderungen bereit für einen Merge nach master sind. Sobald die Implementierung abgeschlossen ist, Beiträge von Team-Mitgliedern eingepflegt und alle Konflikte behoben sind und alle Tests für diesen Branch im grünen Bereich sind, ist dieser bereit für eine Integration nach master.
  • Man führe den Merge durch und veröffentliche, wie man möchte. Manche Teams ziehen es vor, automatisch jede Änderung auszuliefern, sobald diese im master-Zweig ankommt und alle Tests durchlaufen; dieses Vorgehen nennt man Continuous Deployment-Modell. Andere Teams lassen Menschen entscheiden, wann welche Änderungen ausgeliefert werden. Es liegt an Ihnen und Ihrem Team, welchen Weg Sie einschlagen.

Dies ist die Kurzfassung, wie Branching Workflows funktionieren – und wie diese Continuous Delivery dank Git und dessen einfachen Branching praktikabler und simpler machen. Für weitere Fragen steht Ihnen das Team von Braintime jederzeit zur Verfügung.

Das interessiert Sie?

Dann sind wir als Atlassian Platinum Partner für Sie da.

[/jbox]