Hero Image
- Philipp Ludewig

Lektüre unterwegs: Verantwortung, Observability und Refactoring

Heute hatte ich viel Zeit zur Verfügung, als ich im Bus von Momotombo nach León saß. Da Reddit von meinem Mobilfunkanbieter hier in Nicaragua blockiert ist, wandte ich mich meiner zweithäufigst besuchten Website zu: HackerNews. Drei Artikel vielen mir sofort ins Auge und ließen mich in Erinnerungen schwelgen.

Der erste Artikel ist on Graham-Yooll und erinnerte mich an meinen eigenen Karriereweg bei Thoughtworks. Denn er gibt einen wichtigen Rat: "Übernimm Verantwortung, bevor sie dir offiziell übertragen wird.". Ich stimme dieser Aussage voll und ganz zu. Als ich meine Karriere als Graduate Consultant bei Thoughtworks begann, übernahm ich schnell Verantwortung und dachte darüber nach, was ich tun könnte, um mein Team und meinen Tech Lead zu unterstützen. Die Karriere Entwicklung und Feedbackkultur von Thoughtworks fördert ein solches Verhalten. Obwohl die einzige Erwartung in der Rolle eines Graduate Consultants darin besteht, sich auf sich selbst zu konzentrieren. Ich hatte das Glück, mit Tech Leads zusammenzuarbeiten, die mir konstruktives Feedback gaben und mir Türen öffneten, um wertvolle Erfahrungen zu sammeln. Zum Beispiel begann ich, Retrospektiven, Gespräche über technische Schulden und Threat-Modeling-Workshops zu moderieren. Mein Ziel war es immer, zu dem Tech Lead zu werden, mit dem ich selbst gerne zusammenarbeiten würde.

Graham-Yooll betont auch die Bedeutung von Zuverlässigkeit. Einmalige Erfolge sind großartig, aber Manager brauchen die Gewissheit, dass man konstant liefern kann. Als ich bei Thoughtworks zum Senior Consultant befördert wurde, lag das nicht nur daran, dass ich in einem Team die Erwartungen übertroffen hatte. Es lag daran, dass ich diese Leistung über mehrere Teams und Projekte hinweg im Laufe der Zeit nachgewiesen hatte. Um das beweisen zu können, schrieb ich einmal pro Woche meine Erfolge auf und sammelte regelmäßig Feedback von meinen Kolleg:innen. Mit dem aufgezeichneten Feedback und der Liste meiner Erfolge konnte ich im Beförderungsprozess meine konstante Leistung nachweisen.

Der nächste Beitrag stammte von einem Gründer, der über die Schwierigkeiten von Teams schrieb, Observability zu verstehen. In seinem Beitrag "Observability's Past, Present, and Future" schreibt er darüber, warum er denkt, dass Observability immer noch nicht gut funktioniert. Während ich dies las, was sich wie ein Pitch für ein KI-Produkt liest, dachte ich an vergangene Projekte. Ich war verwirrt, weil die Teams, mit denen ich zusammengearbeitet hatte, in meiner Erinnerung nicht so sehr gekämpft hatten, wie Sherwood die Leser glauben machen möchte. Zitat: "Plötzlich funktionierte unser altes Zuverlässigkeits-Playbook nicht mehr. Wir konnten nicht alle Edge-Cases vorhersagen, geschweige denn dafür Tests schreiben. Fehlermodi entstanden zunehmend aus der komplexen Interaktion zwischen Services. Bei der Root-Cause-Analyse reichten Logs und grundlegende Metriken nicht mehr aus."

Ich frage mich, wie diese Tage der Cloud-Adoption gewesen sein müssen. Die Vorstellung, dass mit Microservices die Komplexität so stark gewachsen sei, dass man keine Edge-Cases mehr testen konnte, klingt nach etwas anderem. Das klingt für mich eher danach, dass Teams ihre Teststrategie nach rechts (Produktion) verschoben haben, anstatt sich an der Testpyramide zu orientieren. Ich bin froh, dass wir jetzt DevOps-Metriken wie Change Failures haben, denn diese ermöglichen uns nicht nur einen Einblick in die Entwicklungsphasen von Software, sondern auch in die Effektivität des Prozesses und der eingesetzten Quality Gates.

Zitat: "Instrumentierung dauert ewig. Dashboards sind ständig veraltet. Monitore schlagen Fehlalarm. Alarme fehlt der Kontext. On-Call ist eine permanente Steuer auf die Engineering-Produktivität. Die Lösung von Incidents kann Stunden, manchmal Tage dauern." Sherwoods Punkt ist, dass mit all der Komplexität Dashboards, Monitore und Alarme kamen, die das Team über Probleme im Produktionssystem alarmieren sollten. Da diese Signale zu einer Vielzahl von Signalen anwachsen können, sagt er, dass Observability schlechter geworden ist. Nun, meiner Meinung nach sollte man, wenn man die im Zitat beschriebenen Probleme hat, jeden Monitor und jeden Alarm neu bewerten. Refaktoriere die Trigger und Alarme, die keinen Sinn ergeben, speichere Dashboards als Infrastructure as Code und aktualisiere sie regelmäßig. Dokumentiere auch Rezepte für bekannte Probleme. Ich habe das Wheel of Misfortune ausprobiert und war sofort ein Fan der Trainingsmethode, die Rollenspiele nutzt, um Teams in einem sicheren Raum gemeinsam lernen zu lassen, was bestimmte Signale und Alarme bedeuten könnten. Ähnlich wie bei Feature Toggles ist es ein Anti-Pattern, ihre Anzahl zu stark wachsen zu lassen. Sie müssen einen Wert haben, um bleiben zu dürfen. Das gilt auch für Monitore und Alarme. Und hier kommt der Haken: "Der Aufwand, den wir in Observability stecken, steht NICHT im Verhältnis zu den Fortschritten, die wir bei ihren Zielen gemacht haben: bessere Erkennung, schnellere Root-Cause-Analyse und zuverlässigere Apps." Meiner Meinung nach wird Observability keine zuverlässigeren Apps liefern. Man braucht eine solide Vertical Slice von Quality Gates, um sicherzustellen, dass die Apps keine Ausfallzeiten haben. Die Teststrategie muss in der Lage sein, Edge-Cases zu erfassen, bevor der Commit das Produktionssystem erreicht. Wenn Teams eine Teststrategie anwenden, die dem Swiss Cheese Model folgt, werden sie viel weniger Probleme haben. Ich würde vermuten, dass das neue Unternehmen von Sherwood an einem KI-Tool arbeitet, das darauf abzielt, die Signale für Teams zu verstehen. Die Entwickler müssen jedoch ihre Hausaufgaben machen, um den größten Nutzen aus ihren Observability-Signalen zu ziehen.

Was mich schließlich dazu inspiriert hat, diesen Beitrag zu schreiben, war ein Artikel von Ron Jeffries "Refactoring -- Not on the backlog!". Er argumentiert, dass Refactoring kein separater Backlog-Eintrag sein sollte. Anstatt um dedizierte Zeit zu bitten, um unordentlichen Code aufzuräumen, sollten Entwickler inkrementell refaktorieren, während sie jedes neue Feature erstellen, und den Codepfad aufräumen, den sie benötigen, anstatt ihn zu umgehen. Dieser Ansatz ist leichter zu rechtfertigen, liefert sofortige Vorteile und macht die Entwicklung progressiv schneller. Dies ist auch bekannt als die "Boy/Girl Scout Rule" oder "Hinterlasse den Code besser, als du ihn vorgefunden hast". Jeffries hat diesen Beitrag geschrieben, um uns an diese Regel zu erinnern, und ich könnte mir vorstellen, dass es eine Reflexion dessen ist, was er in seiner täglichen Arbeit sieht. Ich habe selbst gesehen, wie Entwickler vom Refactoring abgehalten wurden, weil es nicht mit dem 'Business Value' eines Tickets übereinstimmt, und dann beobachtet, wie Codebasen verfielen, bis ein großes Refactoring unvermeidbar wurde. Darüber hinaus ist es im Zeitalter der agentenbasierten Softwareentwicklung bereits viel einfacher, Code zu einer Codebasis hinzuzufügen als es aufzuräumen. Es erscheint mir daher nur logisch das Entwickler, angetrieben vom Druck ihrer Organisation, sich mehr um abgearbeitete Tickets scheren als eine sauberen Quellcode.

Allerdings bin ich der Meinung, dass wir Tickets die sich auf technische Schulden konzentrieren immer noch erstellen sollten. Das eigentliche Problem ist doch, ob an den technischen Schulden kontinuierlich gearbeitet werden. Die Gefahr welche ich darin sehe sollten Teams sich nur nach der "Scout" Regel richten, ist dass auf der Seite des Management eine Unklarheit entsteht wo der Fokus der Entwickler:innen liegt. Der technische und business Teil des Teams sollten meiner Meinung nach regelmäßig über ihre technischen Schulden reden. Jede Änderung im Quellcode bringt auf dem einem oder anderen Weg technische Schulden mit sich und es ist besser wenn das allen Beteiligten klar ist. Das Management von technischen Schulden welche akzeptabel und eine Belastung sind, ist dabei das wichtigste. Metriken wie die DevOps Metriken helfen dabei zu messen, wie technische Schulden sich auf den Softwareentwicklungsprozess auswirken. Zudem hilft es Messwerte der wichtigsten Features zu erheben durch sogenannte "fitness functions", Stichwort Evolutionary Architecture.

Hier ein Beispiel aus der Realität:

  • Das Team hatte ein laufendes Produkt in einem Produktionssystem
  • Es gab ein rotierendes Pair Programming pair, dass das Produktionssystem auf Probleme überwacht, genannt Tech and Ticket (TnT). Beide Entwickler:innen lösten gemeinsam die Probleme, was es ihnen ermöglichte, voneinander zu lernen und in Echtzeit konstruktives Feedback zu geben.
  • Ihr Hauptfokus lag auf der Lösung von Problemen der Produktionsumgebung
  • Wenn es kein Produktionsproblem gab, arbeiteten sie an Tech-Debt-Stories
  • Die Tech-Debt-Stories wurden von den Entwickler:innen und Business-Rollen gemeinsam in einem zweiwöchentlichen Grooming-Meeting erstellt/abgesegnet. Auf diese Weise wurden Tech-Debt-Stories von allen Stakeholdern priorisiert, mögliche Lösungen diskutiert und Tickets abgesegnet werden.

Das Team in diesem Beispiel wendete weiterhin die "Boy/Girl Scout Rule" an, um kleinere Probleme zu lösen, und bekam Zeit von den Business-Stakeholdern, um größere technische Schulden zu verbessern. Die Einbeziehung von Business-Stakeholdern in diesen Gesprächen stellte sicher, dass sich das TnT-Paar an technischen Schulden arbeiten durfte, welche von allen Parteien als sinnvoll angesehen wurden.

Als ich Jeffries' Beitrag las, fragte ich mich, wie etwas so Offensichtliches wie die "Boys/Girls Scout" Regel es wert sein könnte, darüber zu schreiben. Aber dann wurde mir klar: Sowohl Sherwoods Observability-Probleme als auch Jeffries' Refactoring-Appell haben dieselbe Ursache. Teams lassen Komplexität akkumulieren, anstatt kontinuierlich Qualität zu pflegen. Ob es sich um Berge von schlecht konfigurierten Monitoren oder verschlungene Codebasen handelt, die Lösung ist die gleiche: Wende die Scout Rule konsequent an. Räume inkrementell auf. Lass nicht zu, dass technische Systeme wie Monitoring-Dashboards oder Code zu unwartbaren Ungetümen werden, die heroische 'dedizierte Zeit' zum Reparieren benötigen. So wie ich bei Thoughtworks gelernt habe, dass konstante kleine Verbesserungen zur Beförderung führen, brauchen unsere Systeme dieselbe Philosophie.

Anmerkung: übersetzt mit KI