Die große Frage bei allen Methoden ist “Wird mein Team dadurch besser?” und ich kann sagen – JA. Bleibt nur noch die Frage warum?
Aber zunächst zur Begriffsklärung: Trunk-Based-Development ist ein Source-Control-Branching-Modell, bei dem die Entwickler gemeinsam an dem Code in einem einzigen Branch namens "trunk" arbeiten. Das Gegenteil davon ist der Git-Flow, bei dem viel mit Branches und Pull-Requests gearbeitet wird.
Das Problem beim Git-Flow ist, dass durch das Verlassen der Mainline der jeweilige Branch, in den die Commits gepusht werden, grundsätzlich alt ist. Je länger dabei die einzelnen Branches parallel zur Mainline laufen, desto weiter entwickeln sie sich exponentiell voneinander weg. Die jeweiligen Commits werden so erst sehr spät zusammengeführt und das Zusammenführen der alten, separat entwickelten Stände führt dann zu Problemen: Den bekannten Merge-Konflikten.
Dazu kommt, um Aussagen über die Qualität der einzelnen Branches zu bekommen, muss jeder Commit in den Branches die gleichen Pipelines durchlaufen wie die Mainline. Bei vielen Commits stellt sich dann die Frage, welcher Commit, auf welchem Branch, welche Pipeline angestoßen oder zerbrochen hat. Darüber hinaus kann nicht sichergestellt werden, welcher Stand aktuell auf der Pre-Prod oder Testumgebung bereitgestellt wurde, um weiter getestet zu werden.
All diese Probleme führen dazu, dass ich mich Dave Farley anschließe, der in seinem aktuellen Talk erklärt, dass Continuous Integration nicht möglich ist, wenn mit Feature Branches gearbeitet wird [1].
Beim Trunk-Based-Development pushen alle Entwickler mindestens ein Mal am Tag ihre Änderungen in die Mainline (oder auch Master oder Trunk), im Idealfall allerdings deutlich häufiger.
Durch die ständige Integration des eigenen Standes in die Mainline kostet es weniger Zeit bis ein Inkrement in Produktion geht. Dementsprechend verkürzen sich die Feedback-Zyklen und die Zeit bis zum ersten Nutzerfeedback. Zudem gibt es direktes zuordenbares Feedback zur Qualität des Inkrements durch die Pipelines.
Erst so wird Continuous Integration wirklich möglich.
Voraussetzung dazu ist es die zu bearbeitenden Inkremente in kleine Teile zu schneiden. Stories oder Sub Tasks dürfen dabei nicht größer sein, als eine Person pro Tag erledigen kann, dabei gilt je kleiner desto besser. Auch sollten alle Entwickler vor dem Hinzufügen des eigenen Standes ein “pull --rebase” ausführen, damit der aktuelle Entwicklungsstand der Mainline geladen wird. Außerdem kann Domain-Driven-Design dabei helfen das System so zu schneiden, dass die Entwickler sich nicht dauernd bei den Commits auf den Füßen stehen.
Wie die Studie von Nicole Forsgren, PhD Jez Humble und Gene Kim zeigt, erhöht sich durch diesen Ansatz der Kollaboration die Teamproduktivität und das Team liefert somit schneller [2]. Dazu kommt, dass die Merge-Hölle beim Zusammenführen der Mainline und der Branches vermieden wird, da diese sich nicht exponentiell voneinander entfernen. Zusätzlich bleibt die Codebasis zu jedem Zeitpunkt releasefähig. Als letzter und wichtigster Punkt bezogen auf Resilienz und Entwicklungsgeschwindigkeit lässt Trunk-Based-Development Continuous Delivery Realität werden, da jedes Feature auch wirklich direkt ausgeliefert wird.
[2] Accelerate: The Science Behind Devops