Blog

Wie können Teams ohne Pull Requests zusammenarbeiten?

FEB 23, 2018

Eine kurze Geschichte über vorab getestete Integration

Emily Bache

Continuous Integration und Code Review stehen in engem Zusammenhang mit Erfolg. Viele nutzen Pull Requests für Code Reviews, doch für Teams, die an einem gemeinsamen Standort arbeiten, kann das ein Hindernis für CI sein. Gibt es einen besseren Weg?

Das (fiktive) Team besteht aus drei Entwicklern: Annika, Boris und Carol. Annika wurde kürzlich direkt von der Universität eingestellt, Boris ist der Teamleiter und Carol ist am längsten dabei. Jeder arbeitet an einer anderen Aufgabe. Als sie heute ins Büro kamen, haben sie alle ihre Arbeit mit ihrem gemeinsamen Master-Branch synchronisiert. Jetzt ist es fast Zeit für den Morgenkaffee. Alle haben Änderungen am Code vorgenommen, die sie mit dem Rest des Teams teilen möchten.

Annika arbeitet an einem lokalen Branch namens „red“. Sie prüft, ob er mit Master auf dem neuesten Stand ist, und pusht ihn in einen Remote-Branch namens „ready/red“. Bei Boris und Carol läuft es ähnlich. Sie arbeiten jeweils an den Branches „blue“ und „orange“ und pushen ihre Änderungen in „ready/blue“ beziehungsweise „ready/orange“.

the three

Der Build Server ist so eingerichtet, dass er neue Branches auf dem Version Control Server erkennt, die einer Namenskonvention folgen. Jeder Branch, der mit „ready/“ beginnt, wird für die Integration eingeplant, und es läuft immer nur einer dieser Integrations-Builds gleichzeitig. Der Build Server delegiert Builds an einen oder mehrere Agents. Da der Agent für den Ready-Job inaktiv ist, übernimmt er die Änderung aus „ready/red“ sofort und lässt die Builds der beiden anderen Ready-Branches in der Warteschlange.

build servers

Der Build-Job besteht aus mehreren Schritten. Zuerst führt der Agent den Ready-Branch mit einer lokalen Kopie des Master-Branches zusammen. Annikas Änderungen werden per einfachem Fast-Forward übernommen. Der Agent führt einen vollständigen Build, eine statische Analyse, eine Prüfung des Code-Stils und Unit-Tests durch. Alles läuft gut, daher pusht der Agent das Merge-Ergebnis auf den Version Control Server und veröffentlicht eine Nachricht im Team-Message-Board.

Bei Boris’ Ready/blue-Branch beginnt es ähnlich. Der Build-Agent erstellt eine Kopie von Master vom Git-Server und führt den Ready-Branch damit zusammen. Das ist kein Fast-Forward-Merge, da Master einen neuen Commit für die Änderungen aus „red“ enthält, aber das ist kein Problem. Solange der Agent den Merge durchführen kann, ohne Konflikte zu finden, kann der Build fortgesetzt werden.

Anschließend fährt der Agent mit den nächsten Build-Schritten fort. Leider hatte Boris nicht bemerkt, dass eine seiner Änderungen zu einem fehlgeschlagenen Test führte. Das Team hat zuvor vereinbart, dass der Code in Master immer alle Tests bestehen soll. Daher sollten Boris’ Änderungen nicht geteilt werden. Der Build-Agent informiert Boris über die fehlgeschlagenen Tests, verwirft seinen zusammengeführten Branch und fährt fort. Als Nächstes ist Carols Ready/orange-Branch an der Reihe. Der Build-Agent beginnt erneut mit einer frischen Kopie des aktuellen Master-Branches vom Git-Server. Auch Carols Änderungen lassen sich problemlos zusammenführen, und diesmal bestehen sowohl Build als auch Tests. Der Build-Agent pusht den Merge-Commit auf den Server und benachrichtigt das Team.

build servers

Boris und Carol trinken einen Kaffee, während sie darauf warten, dass der Build Server ihre Änderungen integriert. Annika spricht mit dem Product Owner über das neue Feature „cyan“, an dem sie als Nächstes arbeiten möchte. Als sie an ihre Schreibtische zurückkehren, sehen sie die Nachrichten vom Build Server.

Annika freut sich, dass ihre Änderungen erfolgreich integriert wurden. Sie ruft den aktuellen Master-Branch vom Remote-Git-Server ab. Ihre Arbeit an der Aufgabe „red“ ist nun abgeschlossen, und ihre Änderungen sollten einem Code Review unterzogen werden. Sie markiert die Aufgabe „red“ im Issue Tracker als erledigt und fügt einen Tagesordnungspunkt für das nächste geplante Code-Review-Meeting des Teams hinzu, das später in dieser Woche stattfindet. Annika wählt eine neue Aufgabe aus und checkt einen lokalen Branch namens „cyan“ von Master aus. Boris sieht die Nachricht über seine fehlgeschlagenen Tests und erkennt sofort, was ihm entgangen ist. Sein Fehler ist ihm etwas unangenehm, aber er freut sich, dass seine Teamkollegen nicht betroffen sind. Vielleicht bemerken sie gar nicht, was passiert ist. Boris nutzt die Gelegenheit, die neuesten Änderungen aus Master in seinen „blue“-Branch zu mergen. Er kann das Problem mit den Tests schnell beheben und pusht ein Update nach „ready/blue“. Der Build-Agent beginnt sofort mit der Arbeit.

Carol ist mit der Aufgabe „orange“ noch nicht fertig, freut sich aber, dass ihre ersten Änderungen erfolgreich integriert wurden. Sie ruft Master ab und führt ihn mit „orange“ zusammen, bevor sie dort weiterarbeitet. Sie hat eine Designänderung entdeckt, die ihre Aufgabe erleichtern würde. Sie plant das Refactoring in Schritten, damit sie kleine Änderungen häufig pushen kann, während sie das Redesign umsetzt. Wenn sie ihre Änderungen regelmäßig mit dem Team teilt, können alle aufwendige Merges leichter vermeiden. Später in derselben Woche betrachtet das Team im Code-Review-Meeting Annikas Änderungen für die Aufgabe „red“. Sie umfassen die Arbeit von einigen Tagen. Das Code-Review-Tool zeigt eine Zusammenfassung aller beteiligten Commits, und sie besprechen sämtliche Änderungen bei der Entwicklung des Features „red“.

Leider sind Boris und Carol mit einem Teil von Annikas Design nicht zufrieden, und die Code-Formatierung muss an einigen Stellen verbessert werden. Das Ergebnis des Meetings ist, dass sie vereinbaren, mit Annika bei einem Refactoring des Designs gemeinsam zu programmieren. Außerdem ermutigen sie sie, während der Entwicklung häufiger informelle Designgespräche anzustoßen. Die erfahreneren Entwickler Boris und Carol sollen Annika dabei helfen, bessere Designfähigkeiten zu entwickeln. Die Probleme mit der Code-Formatierung empfindet das Team als etwas lästig, da solche Details nicht im Mittelpunkt eines Code-Review-Meetings stehen sollten. Sie erstellen eine Aufgabe, um den Code-Style-Checker im Build für vorgetestete Integration zu verbessern, damit ähnliche Probleme mit der Code-Formatierung künftig erkannt werden.

Kommentar

Dieser Entwicklungsprozess funktioniert für Annika, Boris und Carol sehr gut, und vorab getestete Integration ist ein kleiner, aber wichtiger Bestandteil. Sie verwenden keine Pull Requests, haben aber Prüfungen dafür eingerichtet, welcher Code in den Master-Branch gelangen darf, und leben eine gute Kultur für Code-Reviews. Die Integration in den Master-Branch erfolgt häufiger als der Durchlauf der Arbeitselemente. Das ist wichtig. Je öfter ihr integriert, desto weniger aufwendig wird die Integration. Außerdem möchtet ihr eure Arbeitselemente vielleicht nicht in dieselben kleinen Einheiten aufteilen, die für Codeänderungen ideal wären. Ebenso möchtet ihr die Integration nicht unbedingt verzögern, indem ihr darauf wartet, dass ein Teamkollege euren Pull Request prüft.

Streng genommen ist dieser Prozess keine Trunk-Based Development, da neben dem Trunk weitere Branches beteiligt sind. Solange die Integration in der Praxis jedoch häufig erfolgt, ist kein Unterschied erkennbar. Der Vorteil gegenüber Trunk-Based Development besteht natürlich darin, dass Boris oder ein anderer Entwickler den Master-Branch nicht versehentlich für den Rest des Teams beeinträchtigen kann.

Wenn ihr Jenkins verwendet, könnt ihr den Integrationsprozess mit unserem Pretested Integration plugin einfach automatisieren. Bei anderen Build-Servern ist es nicht schwierig, diese Funktionalität selbst umzusetzen. Unabhängig davon, welchen Ansatz euer Team wählt, empfehle ich euch, einen Prozess zu etablieren, der häufige Integration mit kollaborativen und konstruktiven Code-Reviews verbindet.

  • CI/CD

Subscribe to our newsletter