zurück zum Artikel

Nachgebessert: Pull-Request-Workflows in der Praxis

Architektur/Methoden
Nachgebessert – Pull-Request-Workflows in der Praxis

(Bild: Shutterstock / iX)

Code-Reviews auf Basis von Pull Requests fördern nicht nur den Wissens- und Meinungsaustausch im Team, sie machen außerdem den Projektfortschritt nachvollziehbar. Die Reviews bergen aber auch Konfliktpotenzial und sind zeitaufwendig. Sorgfältige Planung ist daher essenziell.

Code-Reviews sind eine feine Sache: Sie dienen dazu, verschiedene Meinungen einzuholen, Wissen zu teilen und nicht zuletzt den Fortschritt im Projekt konkret und greifbar zu machen. Alle Kollegen lernen mit der Zeit automatisch hinzu. Code-Reviews kosten aber auch Zeit und können zu unangenehmen Konflikten im Team führen. Wie sollte daher ein zeitgemäßer Pull-Request-Workflow aussehen und wie lassen sich dabei trotz der verpflichtenden Reviewzyklen Beeinträchtigungen des Projektfortschritts vermeiden?

Gründe für Pull Requests

Neben den genannten Gründen, die für ein verpflichtendes Code-Review über Pull Requests sprechen, tragen sie auch zu höherer Konsistenz der Umsetzung (einheitlicher Stil, Lesbarkeit) in einem Projekt bei. Abweichungen von Konventionen lassen sich damit ebenso erkennen wie andere verwandte Probleme. Letztlich verringert sich dadurch auch die langfristig immer entstehende technische Schuld.

Ein Code-Review stellt auch eine gemeinsame Diskussionsbasis dar – trotz Brainstorming, Akzeptanzkriterien und Whiteboards steht die Wahrheit letztlich doch nur im Code. Missverständnisse, Lücken und Verbesserungspotenzial werden ersichtlich. Weiterhin funktionieren Pull Requests asynchron, sodass jeder Kollege Code-Reviews in seinen Arbeitstag eintakten kann (vergleichbar zu E-Mail). Das hilft auch bei der Arbeit in verteilten Teams und unterschiedlichen Zeitzonen.

Integration in den agilen Entwicklungsprozess

Technisch sind Pull Requests stark an die Arbeit im Versionsverwaltungssystem Git (beispielsweise Gitflow [1]) gekoppelt – wobei dieses allerdings keine Bedingung ist. In vielen Teams sieht ein agil geprägter Entwicklungsprozess folgendermaßen aus (Kurzfassung):

  1. Ein Thema (z.B. Feature) wird in einem Ticket (Story) hinsichtlich der Anforderungen konkretisiert
  2. Besprechung der Story in Grooming/Planning, Schärfung der Akzeptanzkriterien
  3. Sofern nötig/gewünscht erfolgt eine Schätzung
  4. Product Owner legt Prioritäten der Storys im Rahmen des Sprints fest
  5. Entwicklung startet und ein neuer Branch wird ausgehend vom Entwicklungszweig erstellt
  6. Nach Abschluss der Entwicklung und Aktualisierung/Durchlauf der Tests erfolgt das Review via Pull Requests
  7. Nach Abnahme wird der Branch wieder mit dem Hauptzweig zusammengeführt (Merge)
  8. Gegebenenfalls Deployment auf Testumgebung und Abnahme/QA
  9. Je nach Releasezyklus werden Entwicklungszweig und Master-Branch zusammengeführt
  10. Das Release erfolgt (alternativ: Continuous Deployment)

Die beschriebene Abfolge dürfte inzwischen gängig und etabliert sein, wobei es natürlich je nach Personalsituation, Unternehmen und den individuellen Vorerfahrungen Abweichungen gibt.

Review-Konstellationen

In der Ausgestaltung des Pull-Request-Workflows finden sich definitiv Unterschiede. Folgende Ausprägungen sind nach den Erfahrungen des Autors in Teams mit mindestens drei und maximal zehn Entwicklern in der Praxis gängig.

Es ist generell empfehlenswert, alle Kollegen zu informieren. Dadurch kommt es zwar zu einem gewissen "Grundrauschen" in der Kommunikation, das von manchem als störend empfunden wird. Das Problem sollte dann im Rahmen einer Retrospektive diskutiert werden.

In den meisten Projekten sollte es sich als ineffizient erweisen, alle Kollegen alles reviewen lassen. Ein alleiniger Lead-Engineer bildet wiederum häufig einen Flaschenhals. Bewährt hat sich ein Minimum von zwei Reviewern. Die sollte das Team entweder nach dem Schema Junior/Senior nominieren oder aus den gerade verfügbaren Kollegen rekrutieren.

Idealerweise können alle Entwickler eines Teams jeden Pull Request reviewen. Häufig scheitert das aber an Spezialisierungen, Vorwissen oder auch Unwillen. Gerade in kleineren Teams finden sich die möglichen Reviewer daher meist "automatisch". Unabhängig von Spezialisierungen finden sich zahlreiche Aspekte wie Lesbarkeit, Kommentare, Namensgebung, Methodenlänge oder Strukturierung, die in jedem Pull Request relevant sind. Insofern kann wertvoller Input auch von Kollegen aus anderen "Welten" einfließen. Letztlich sind regelmäßige Reviews oft auch ein wichtiger Schritt auf dem Weg der Weiterentwicklung zum Fullstack-Entwickler.

Bleibt noch die Frage, wie die Kollegen von einem neuen Pull Request erfahren? Sitzen alle im selben Büro, kann ein Zuruf genügen. Praktischer ist aber ein eigener Channel im Chat. Der Autor des Pull Request schreibt dann eine kurze Nachricht. Alternativ lässt sich die Benachrichtigung über Tool-Integrationen wie Bitbucket und Slack automatisieren.

Praxis im Projekt und Tooling

Generell ist es sinnvoll, ein gemeinsames Vorgehen für den Pull-Request-Workflow im Kickoff eines Projekts festzulegen – vergleichbar zu Definition of Done/Definition of Ready. Dabei entstehen gemeinsame Konventionen, wie sie die folgenden Beispiele kurz beschreiben:

Manche Teams verwenden dazu auch Checklisten, die jeder Pull Request abzuarbeiten hat – auch in Bezug auf Continuous Integration. Die bekanntesten Werkzeuge für die Bearbeitung von Pull Requests sind sicherlich die in die jeweiligen Plattformen integrierten Ansichten von GitHub und Bitbucket. Vieles lässt sich darin bereits ableiten – links stehen die geänderten Dateien, rechts eine Diff-Ansicht inklusive (gewichtetem) Kommentar, Reaktion und einer kleinen Task-Funktion zur Kennzeichnung (s. Abb. 1).

Nachgebessert – Pull-Request-Workflows in der Praxis
Darstellung von Pull Requests in Bitbucket mit Kommentaren (Abb. 1)

Eine Reaktion nach dem Review sollte verpflichtend sein (Bringschuld Reviewer), um regelmäßige Nachfragen zum Status zu vermeiden. Andererseits sollte auch jeder Kommentar eine Antwort erhalten (Bringschuld Autor). Darüber hinaus ist eine Offline-Diskussion zu begrüßen, deren Ergebnis kommentiert in den Pull Request einfließen sollte.

Häufig verzögern sich Pull Requests, weil keines der Teammitglieder nur auf neue Code-Reviews wartet. Um eine kontinuierliche Betreuung der Pull Requests sicherzustellen, helfen einfache Regeln. Empfehlenswert ist beispielsweise, dass jeder Kollege morgens oder nach der Mittagspause offene Pull Requests bearbeitet – je nach Aufkommen gegebenenfalls auch zweimal am Tag.

Eine Frage des Typs

Entwickler sind Menschen und ein Pull-Request-Workflow erfordert Interaktion. Die folgenden Tipps und Hinweise auf Basis pointierter Typprofile sollen helfen, einen akzeptablen und wirkungsvollen Pull-Request-Workflow zu etablieren und den Umgang mit häufig auftretenden Problemen zu meistern.

Der Kritiker: Er begreift Pull Requests als essenziellen Teil seiner Arbeit und überprüft jeden Pull Request sofort. Das bindet einen Großteil seiner Zeit, worunter die eigene Zuarbeit zu Storys aus dem Sprint leidet.

Ein solches Verhalten ist sicherlich Thema in einer Retrospektive. Eine Lösungsmöglichkeit ist die gezielte Nominierung der Reviewer. Eine weitere Option ist die Beschränkung auf maximal einen Review pro Tag und Entwickler.

Der Stumme: Er hat keine Meinung oder empfindet Pull Requests als störend. Einen Review führt er allenfalls nach Aufforderung durch. Andere Kollegen müssen einspringen, wodurch sich der Review-Prozess verzögert.

Hier hilft auch die Retrospektive und ein sich hoffentlich entwickelndes Verständnis vom Mehrwert, den Pull Requests bieten. In der Regel gleicht sich das Review-Verhalten immer weiter an, je länger ein Team zusammenarbeitet. Es bleibt eine stetige Herausforderung für jedes Team eine Mischung aus Code-Review und der eigentlichen Entwicklung zu finden. Um es den Reviewern dabei so leicht wie möglich zu machen, helfen kompakt gehaltene Pull Requests, gute Beschreibungstexte, Screenshots bei UI-Änderungen oder auch Begründungen für Entscheidungen.

Der Abnicker: Er sieht sich gern Pull Requests an und genehmigt die meisten sofort. Nur gelegentlich erfolgt eine Anmerkung und wenn dies geschieht ist der Mehrwert überschaubar.

Dieses Verhalten ist oft bei Junior-Entwicklern zu beobachten, die zwar gern Code der erfahreneren Kollegen lesen, aber wenig beizutragen haben. Letztlich ist dies auch nachvollziehbar. Unzureichende Teilnahme ist natürlich auch ein Hinweis auf Schulungsbedarf. Der Autor kann Feedback fördern, indem er Stellen kennzeichnet, bei dener er sich nicht sicher ist beziehungsweise Feedback wünscht.

In eingespielten Teams werden Pull Requests oft von erfahrenen Entwicklern schnell genehmigt, da sie sich bereits einen guten Ruf erarbeitet haben. Hier ist es eine Frage der Disziplin, auch deren Code entsprechend zu prüfen – jeder macht Fehler und Verbesserungspotenzial gibt es eigentlich immer.

Der Tüftler: Er vergräbt sich gern in komplexe Themen und teilt diese nur selten in kleinere Unteraufgaben. Alle Tests sind stets sauber, komplett und dokumentiert, bevor er einen Pull Request erstellt. Leider führt dies dazu, dass die Pull Requests umfangreich sind und erst nach mehreren Tagen vorliegen. Die Reviewzyklen dauern lange und Features lassen sich häufig nicht mehr im Rahmen des Sprints abnehmen, da die Zeit nicht ausreicht.

Das kommt recht häufig vor und verlangt vom Team ein gemeinsames Abwägen zwischen Pragmatismus und technischer Exzellenz. Ein guter Mittelweg ist die Erstellung eines technischen Gerüsts (Scaffolding) mit dem technischen Lösungsansatz ohne Feinarbeit und Tests. Das muss natürlich etwa über ein eindeutiges Tag wie [WIP] (Work-in-Progress) gekennzeichnet werden. In der Regel kommt hier auch der meiste Input. Die weitere Arbeit mit Struktur, Optimierung, Kommentaren und Tests erfolgt nachgelagert, sofern der Grundansatz diskutiert und abgesegnet ist. Weitere Pull Requests fallen dann auch automatisch kleiner aus.

Der Kenner: Er verbringt viel Zeit in Reviews und hat stets viele Anmerkungen, die sachlich und fachlich korrekt sind. Er kennt alternative Bibliotheken, weist auf Blogposts oder Design Patterns hin und merkt alternative Lösungsansätze an. Die Diskussion mit ihm kostet aber viel Zeit und verbessert das Ergebnis nur wenig.

Auch dieses Verhalten ist nicht selten und der Input natürlich grundsätzlich wertvoll. In der IT gibt es nahezu immer mehrere Wege, die zum Ziel führen, sodass im Zweifel entscheidend ist, ob die vom Autor gewählte Lösung den Anforderungen genügt und Alternativen keine signifikanten Vorteile versprechen.

Reviewer sollten Kommentare selbst einstufen, damit der Feedback-Loop effizient bleibt. Folgende Level sind denkbar:

Als Konvention empfiehlt es sich, die Einordnung als erstes Wort des Kommentars im Pull Requests zu setzen – so wie auch die Ticketnummer in einem Commit-Kommentar am Anfang steht.

Verhalten und Entscheidungen bei Konflikten

Konflikte sind normal, da jeder Entwickler eigene Vorkenntnisse, Präferenzen und Schwerpunkte hat. Eine gewisse "Storming"-Phase ist daher bei Einführung eines Pull-Request-Workflows auch zu akzeptieren. Letztlich geht es nur über eine gesunde Kommunikationskultur mit gegenseitigem Respekt. Sofern eine Diskussion aber ausufert, sollten sich die Kollegen persönlich besprechen, anstatt die Auseinandersetzung in endlosen Threads in den Kommentaren ausufern zu lassen. Kommt keine Einigkeit zustande, sollten weitere Kollegen hinzugezogen werden. Um eine Diskussion abzukürzen, kann je nach Thema auch eine Umfrage im Chat helfen – beispielsweise mit dem Poll-Plug-in von Slack [2].

Grundsätzlich hilft vor allem die Retrospektive, das gemeinsame Vorgehen und den Prozess immer weiter zu schärfen. Findet sich keine Lösung, muss im Zweifel der Product Owner auf Basis der Fachlichkeit und der entstehenden oder entstandenen Aufwände und Konsequenzen entscheiden. In einem konstruktiv und mit gegenseitigem Respekt arbeitenden Team dürfte das aber nur selten notwendig sein.

Fazit

Sollte im Team bisher kein Pull-Request-Workflow etabliert sein, so ist dessen Einführung zunächst als Investition zu betrachten, da sich die Performance des Teams zumindest vorübergehend verringert. Langfristig gleicht sich das in der Regel wieder aus, vor allem wenn ein Team über längere Zeit zusammenarbeitet und auch das entstandene Produkt betreibt (build/ship/run it).

Gerade in Krisensituationen oder vor einem Release zahlt es sich aus, wenn mehrere Kollegen einen kritischen Bug fixen können oder zumindest auskunftsfähig sind. Code-Reviews sind keine Bedingung, aber ein sehr nützliches Werkzeug für ein gemeinsames Qualitätsverständnis, eine wartbare Codebasis sowie ein anhaltendes Training on the Job. (map [3])

Jan Petzold
ist derzeit als Architekt im Automotive-Bereich in Berlin tätig. Er hat mehrere Jahre als Entwickler gearbeitet sowie als technischer Projektleiter nationale und internationale Entwicklerteams geleitet.


URL dieses Artikels:
http://www.heise.de/-4341944

Links in diesem Artikel:
[1] https://datasift.github.io/gitflow/IntroducingGitFlow.html
[2] https://slack.com/apps/A0HFW7MR6-simple-poll
[3] mailto:map@heise.de