Kolumne: DevOps Stories

(Un)regelmäßige Integration: Stolpersteine für Continuous Integration

Konstantin Diener

© S&S_Media

Nur noch wenige Stunden bis zum Sprint-Review. Das MusicStore-Team arbeitet intensiv daran, letzte Stories fertigzustellen.

  • Martin: „Tschakka, Erster!“
  • Christian: „Hä?“
  • Martin: „Ich habe meinen Feature Branch in den Master gemergt. Das war ein hartes Stück Arbeit. Ihr müsst bei euren Branches aufpassen. Ich habe vor allem in den Services für den Recommender und die Timeline einiges geändert.“
  • Christian: „Super, ich auch. Und wenn ich das richtig verstanden habe, hat Lukas dort auch einiges geändert.“
  • Lukas: „Ja, habe ich.“
  • Christian: „Und Martin ist noch stolz drauf, dass wir jetzt die Merge Hell haben! Danke, Martin. Wir haben noch zwei Stunden bis zum Review und dürfen das jetzt unter Hochdruck zusammenpuzzeln.“
  • Martin: „Sorry, aber das Feature war echt knifflig. Ich habe ja beinahe den ganzen Sprint für die Entwicklung gebraucht.“
  • Ruben: „Der Build nach deinem Merge ist gerade gelaufen. Ich hätte erwartet, dass einiges an Tests dazukommt. Die Anzahl der Testfälle ist aber fast gleich geblieben.“
  • Martin: „Ich habe doch gesagt, dass das Feature knifflig war. Für zusätzliche Tests hatte ich keine Zeit!“
  • Ruben: „In unserer Definition of Done steht doch aber, dass es für jede Klasse Tests gibt.“
  • Martin: „Die gibt es ja auch. Nur halt nicht für die neuen Funktionen.“
  • Christian: „Na, das ist doch sowieso egal. Ein Teil der vorhandenen Tests schlägt seit ungefähr einer Woche fehl, und das interessiert hier auch niemanden.“
  • Martin: „Aber ich musste doch das Feature fertigmachen, damit wir es im Review zeigen können …“
  • Lukas: „Wie möchtest du das Feature denn im Review zeigen? Die Tests schlagen fehl und der Build ist rot. Der neue Code ist also nicht auf der Demo-Environment deployt worden.“
  • Martin: „Ups, stimmt. Wollen wir dann die Tests fürs Review ausschalten und danach wieder an?“
  • Christian: „Was ein Quatsch. Dann können wir deinen Kram gleich von Hand auf der Umgebung deployen!“
  • Martin: „Aber dann hätten wir doch keine Continuous Integration mehr.“
  • Ruben: „Haben wir die denn jetzt?“

Continuous Integration heißt …

Rubens Frage ist absolut berechtigt. Ja, das Team hat einen Continuous-Integration-Server, der auf Änderungen im Versionskontrollsystem reagiert, den Build durchführt und im Erfolgsfall das entstandene Artefakt auf eine Umgebung deployt. Aber bringt dieser Prozess dem Team im aktuellen Zustand irgendeinen Erkenntnisgewinn?

Continuous Integration (CI) soll uns helfen, möglichst schnell Feedback zu Änderungen am Sourcecode zu bekommen. Wir sollen Probleme direkt entdecken und beheben, solange die Behebung noch relativ einfach ist. Obwohl das MusicStore-Team einen CI-Server einsetzt, sorgt der aktuelle Zustand seines Prozesses nicht dafür, dass sie Probleme möglichst schnell entdecken können. Suzie Prince nennt diesen Zustand in einem Blog-Post „CI Theatre“. Es sieht von außen wie CI aus, ist es aber nicht.

DevOpsCon Istio Cheat Sheet

Free: BRAND NEW DevOps Istio Cheat Sheet

Ever felt like service mesh chaos is taking over? As a follow-up to our previous cheat sheet featuring the most important commands and functions, DevOpsCon speaker Michael Hofmann has put together the 8 best practices you should keep in mind when using Istio.

… alle Entwickler integrieren ihre Arbeit mindestens einmal am Tag in den Trunk

Das erste Anzeichen für CI Theatre äußert sich darin, dass Martin offenbar über eine längere Zeit Software auf einem Branch entwickelt hat. Damit steht er wohl auch nicht alleine. Ein wichtiges Prinzip von CI nach Martin Fowler lautet aber: Alle Entwickler führen mindestens einmal am Tag in einer gemeinsamen Mainline oder Trunk bzw. Master ihre Änderungen zusammen. „Everyone Commits To the Mainline Every Day“. Mehr dazu findet sich im Kasten „Continuous-Integration-Praktiken“.

Continuous-Integration-Praktiken

  1. Maintain a Single Source Repository
  2. Automate the Build
  3. Make Your Build Self-Testing
  4. Everyone Commits To the Mainline Every Day
  5. Every Commit Should Build the Mainline on an Integration Machine
  6. Fix Broken Builds Immediately
  7. Keep the Build Fast
  8. Test in a Clone of the Production Environment
  9. Make it Easy for Anyone to Get the Latest Executable
  10. Everyone can see what’s happening
  11. Automate Deployment

Prince vertritt die Meinung, dass es ein unabdingbarer Grundstein für CI ist, mindestens einmal am Tag seinen Code in den Master einzuchecken – schließlich verdankt das Verfahren seinen Namen dieser kontinuierlichen Integration. Die Entwickler aus dem MusicStore-Team tun das nicht, weil sie auf langlebigen Feature-Branches arbeiten. Diesen Zustand nennt Prince „Continuous Isolation“.

Dave Farley schreibt in einem Blogpost, dass seiner Meinung nach Feature Branches und CI nicht zusammenpassen. Er geht so weit, dass er Entwicklern empfiehlt, vollständig auf Branches zu verzichten. Da alle Entwickler isoliert auf ihren Branches arbeiten, bekommen wir erst Feedback zur technischen Qualität unserer Arbeit, wenn wir fertig sind. Das ist in der Regel sehr spät. Außerdem ist es sehr riskant, dass Martin, Lukas und Christian dieselben Komponenten umfangreich in isolierten Branches anpassen. Die Konsequenz dieses Vorgehens haben sie wohl schon mehrfach zu spüren bekommen: die sogenannte „Merge Hell“. Es wird nur sehr schwer möglich sein, aus den unterschiedlichen Änderungen am Ende des Sprints eine konsistente Version zu erzeugen („branching is not the problem, merging is the problem“, Jez Humble). Martin ist beruhigt, dass er als erster der drei seine Änderungen in den Master gemergt hat. Das war sehr einfach, weil es zum Master keine Abweichungen gab. Die anderen beiden werden jetzt in einem langwierigen, fehleranfälligen, manuellen Prozess versuchen herauszufinden, wie seine Änderungen zu ihren passen (können).

Als Alternative schlagen Dave Farley und Jez Humble „Trunk Based Development“ (TBD) oder auch „Develop on Mainline“ vor. Hier arbeiten die Entwickler ausschließlich auf der Mainline ihres gemeinsamen Repositories. Diese Version wird vom CI-Server auch für den Build verwendet. TBD setzt auf „earliest integration“, wohingegen Feature Branches in der Regel eher „late integration“ sind.

Dieses radikale Prinzip wirft direkt Fragen auf. Die häufigsten stehen im Zusammenhang damit, Releases auszuliefern. Wie gehen wir damit um, dass die Features auf der Mainline die meiste Zeit unfertig sind? Was passiert, wenn etwa aus der Mainline ein Bugfix-Release gebaut werden muss?

Zunächst muss aller Code so geschrieben sein, dass er die Stabilität der gesamten Software nicht gefährdet. Vor allem bei größeren Änderungen wie Refactorings gibt es immer wieder Entwicklungsteams, die dieses Prinzip außer Acht lassen. Die Änderungen führen dazu, dass die Codebasis über eine längere Zeit in einem instabilen Zustand ist. Die Situation ähnelt einer Autobahnbaustelle. Dort wird der entsprechende Autobahnabschnitt für die komplette Bauzeit voll gesperrt. Mit TBD ändert sich das Vorgehen hin zu dem, was bei Autobahnbaustellen weit gebräuchlicher ist. Es gibt keine Vollsperrung und der Verkehr kann zu jedem Zeitpunkt fließen, während gebaut wird. Humble und Farley sprechen von „Keeping Your Application Releasable“ [1].

Wie entsteht jetzt aber aus der Mainline ein Release? Die gängigste Variante sind Dark Releases. Der Zeitpunkt des Releases, das Ausliefern eines Features oder dessen Teilen wird vom Zeitpunkt der Live-Schaltung getrennt. Das Feature wächst für den Benutzer unsichtbar im Hintergrund und wird sichtbar, wenn es fertig ist. Dazu lassen sich beispielsweise Feature Toggles oder Build Time Switches verwenden.

Eine weitere Möglichkeit besteht darin, dass ein Release-Engineer einen kurzlebigen Release Branch anlegt. Aus diesem Branch baut er anschließend ein entsprechendes Release. Die Entwickler können währenddessen ganz normal auf der Mainline weiterarbeiten.

… alle Entwickler holen sich Feedback über automatisierte Tests und Deployments

CI ermöglicht es uns in verschiedenster Form, die Auswirkungen unserer Softwareänderungen zu ermessen. Beispielsweise können wir feststellen, ob unsere Änderungen strukturell zu denen der anderen Entwickler passen. Gibt es die Methode noch, die mein Code verwendet? Hat sie noch dieselbe Signatur?

Wir wollen aber natürlich auch wissen, ob die Software weiterhin fachlich korrekt funktioniert und auf einer realen Umgebung ausführbar ist. Martin möchte möglichst viele Features für das Feedback der Stakeholder im Review vorbereiten. Dabei lässt er außer Acht, dass ihm schon der CI-Prozess Feedback liefern kann. Dazu hätte er allerdings für seine Änderungen auch entsprechende Tests schreiben müssen. Ein CI-Prozess in Verbindung mit einer unzureichenden oder gar fehlenden Testbasis ist weitgehend wertlos. Dass der Build durchläuft, beweist nur, dass es keine Compilerfehler gibt. Aber nicht, ob die Software funktioniert.

Unittests im CI-Prozess bringen schon eine ganze Menge an Feedback. Den vollen Umfang bekommen wir, wenn der Code auch noch auf einer realen Umgebung deployt und getestet wird.

… der Build ist (wenn überhaupt) nur sehr kurz rot

Tests scheinen im MusicStore-Team im Moment keinen großen Stellenwert zu haben. Nicht nur, dass Martin keine neuen geschrieben hat, auch die bestehenden schlagen fehl. Niemand kümmert sich darum. Diese Situation ist ähnlich riskant wie die Verwendung der Feature Branches. Wenn sich jemand schlussendlich der Tests annimmt, hat der Code seit dem letzten stabilen Zustand schon sehr viele Änderungen erfahren und es wird sehr schwierig, die Ursache zu ermitteln und zu korrigieren.

Deswegen zitiert Martin Fowler Kent Beck mit den Worten „nobody has a higher priority task than fixing the build”. Das ist vergleichbar mit dem “stop the production line”-Prinzip aus der Lean Production. Eine unzureichende Testbasis oder ein über lange Zeit fehlschlagender Build-Prozess sind laut Prince neben seltener Integration die wichtigsten Symptome von CI Theatre.

Das MusicStore-Team hat sich direkt nach dem Sprint-Review mit der Reparatur des Builds beschäftigt. Außerdem sind sie dazu übergegangen, auf der Mainline ihres Versionskontrollsystems zu entwickeln.

Geschrieben von
Konstantin Diener
Konstantin Diener
Konstantin Diener ist CTO bei cosee. Sein aktueller Interessenschwerpunkt liegt auf selbstorganisierten Teams, agiler Unternehmensführung, Management 3.0 und agiler Produktentwicklung. Daneben entwickelt er noch leidenschaftlich gerne selbst Software. Twitter: @onkelkodi
Kommentare

Hinterlasse einen Kommentar

Hinterlasse den ersten Kommentar!

avatar
4000
  Subscribe  
Benachrichtige mich zu: