Seit nun fast zwei Jahren bin ich für die codecentric AG bei einer führenden deutschen Versicherung als Consultant und Developer im Einsatz. Der Kunde selbst hat, wie so oft in der Versicherungsbranche, sehr alte Systeme und traditionelle Arbeitsweisen. Das führt dazu, dass Entwicklungszyklen für neue Produkte mehr als ein Jahr dauern und mit sehr viel organisatorischem Overhead verbunden sind. Auch agiles Arbeiten steckt bestenfalls in den Kinderschuhen, meist werden Projekte im Wasserfall umgesetzt. Das sollte sich mit unserem neuen Projekt ändern.
Das Ziel des Projektes war es, schnell neue Produkte launchen zu können, um sowohl innovativ zu sein, als auch schneller auf Marktveränderungen zu reagieren. Hierfür wollte der Kunde das System der Zukunft bauen, auf dem alle Privatkundenprodukte verkauft werden sollen. Dieses System sollte mit aktuellen Technologien gebaut werden und die alten, sehr monolithischen Systeme über die Zeit ablösen. Auch die allgemeine Arbeitsweise sollte sich ändern. Der Kunde wollte agil werden und deshalb sollte die Umsetzung mit agilen Teams und SAFe erfolgen.
Der Start – Teambuilding
Das Projekt ist mit acht Teams gestartet, die über SAFe einzelne Product Increments umgesetzt haben, die in mehreren Sprints geplant wurden. Die Teams waren alle gemischt gestaffed (codecentricer*innen und Mitarbeiter*innen vom Kunden). Der Kunde hatte auch getrennte Teams in die Diskussion eingebracht, uns als codecentric waren aber gemischte Teams sehr wichtig und wir haben den Kunden letzten Endes davon überzeugen können. Gemischte Teams sind mir persönlich immer sehr wichtig, da ich durch die Nähe zu den Kolleg*innen beim Kunden besser coachen kann und somit die Transformation beim Kunden noch besser unterstützen kann.
Bei uns im Team waren wir drei codecentricer*innen (zwei Devs und ein Agile Coach) und fünf Mitarbeiter*innen vom Kunden (PO, zwei Devs und drei Fachkolleg*innen). Die crossfunktionale Arbeitsweise in Teams mit dem Tech- und Fachbereich war für das Unternehmen ebenfalls ganz neu. Von den kundenseitigen Kolleg*innen bei uns im Team waren die meisten wirkliche „Urgesteine”, mit teilweise mehr als 20 Jahren Unternehmenszugehörigkeit. Auch das agile Vorwissen war beim Kunden nur sehr begrenzt vorhanden und viele Kolleg*innen hatten noch nie agil oder auch nur „hybrid” gearbeitet. Trotzdem habe ich schon nach kurzer Zeit feststellen dürfen, wie wissbegierig, aufgeschlossen und motiviert die Kolleg*innen waren.
Technischer Rahmen
Da wir für ein großes etabliertes Unternehmen tätig waren, war der technische Rahmen abgesteckter, als er beispielsweise bei einem Startup wäre. Dafür war bereits am ersten Tag sehr viel da, z. B. Pipelines, Kubernetes-Cluster, Kafka standen uns direkt von Beginn an zur Verfügung.
Mithilfe von Domain Driven Design haben wir in Event Stormings die einzelnen Fachdomänen identifiziert und so die Zuständigkeitsbereiche der einzelnen Teams ermittelt. Unsere Architektur haben wir sehr Event-Driven aufgebaut, sodass zwischen den einzelnen Fachdomänen in der Regel mit Kafka-Events kommuniziert wurde. Da ich weder der DDD- noch der Kafka-Experte war, habe ich hier nur mitgemacht und nicht mitgestaltet. Dafür konnte ich aber über die Projekt-Laufzeit noch viel über DDD als Methodik und Kafka als Technologie lernen.
Den Code selbst haben wir hexagonal aufgebaut, um langfristig leichter mit Änderungen in Technologien oder Systemen umgehen zu können. Obwohl es viele Vorgaben an die Technologie gab (Angular im Frontend, Spring Boot im Backend), gab es auch viel Handlungsspielraum: so haben wir beispielsweise Kotlin im Unternehmen etablieren können und auch Helm Charts eingeführt. Beides hat mir viel Spaß bereitet!
Hindernisse
Jedes Projekt bringt seine ganz eigenen Hindernisse mit, so war es auch bei uns. Dadurch, dass wir für ein großes Unternehmen tätig waren, hatten wir teilweise sehr langsame Entscheidungsprozesse, auf die wir in der Handlungsebene nicht immer Einfluss nehmen konnten. Außerdem waren viele der bestehenden Build- und Deployment-Prozesse nicht mehr zeitgemäß und eigneten sich nicht wirklich für die schnellen Release-Zyklen, die wir erreichen und etablieren wollten. Auch Dinge wie Datenbankzugriffe waren viel kritischer und schwieriger zu bekommen als zum Beispiel in einem Startup, sodass DevOps (was auch für den Kunden das Ziel war) nur schwer zu etablieren war.
All diese Hindernisse lösen sich bekanntlich nicht von selbst und konnten auch für uns nicht in kurzer Zeit gelöst werden. Mich freut es jedoch, dass der Kunde gewillt war, sich zu verbessern. Leider werde ich die Resultate hierzu aber vermutlich in meiner Zeit im Projekt nicht mehr sehen können, da der Weg hierfür zu weit ist. Gut und spannend war auf jeden Fall, dass wir als codecentric hier mit unserer Erfahrung auf die langfristige Lösung Einfluss nehmen konnten und so den Kunden nachhaltig und langfristig verbessert haben. Mich persönlich spornt das an, da ich dadurch nicht nur punktuell durch meine Projektarbeit unterstütze, sondern auch meinen individuellen Beitrag zu langfristigen Verbesserungen als erfahrener Berater geben kann.
Herausforderungen
Über die lange Zeit, die ich im Projekt war, haben wir im Team und im Gesamtprojekt viele Herausforderungen gehabt. Berichten möchte ich euch von zweien, die mich persönlich am meisten betroffen haben und durch die ich viel gelernt habe.
Verantwortlichkeiten
Meine „Lieblings”-Herausforderung in diesem Projekt war die Verantwortlichkeit für mein Team. Nach dem Go-Live ist uns im Team früh aufgefallen, dass uns durch den gewählten Bounded-Context-Schnitt die Arbeit ausgeht. Denn oft waren wir an den dringenden Features nicht genügend beteiligt – und unsere eigenen Features waren durch externe oder interne Abhängigkeiten blockiert.
Ein Indiz dafür, dass wir vermutlich unsere Software nicht gut geschnitten haben, da wir als Team nicht autonom genug waren.
Dieser mangelnde Freiraum und der fehlende, klar abgegrenzte Verantwortungsraum haben unser Team stark frustriert. Eine Frustration, die über die Zeit nicht besser wurde, da sich nach ein paar Monaten abzeichnete, dass interessante und wertschöpfende Aufgaben erstmal für unser Team nicht umsetzbar waren, da sich die Abhängigkeiten nicht zeitnah auflösen ließen. Außerdem haben die vielen internen Abhängigkeiten dazu geführt, dass wir als Gesamtprojekt immer langsamer wurden. Zeitweise habe ich mich gefühlt, als ob wir als Gesamtprojekt einen verteilten Monolithen gebaut hätten.
Um das Problem zu adressieren, sind wir aus unserem Team heraus in die Initiative gegangen und haben uns hauptsächlich mit unseren Architekt*innen in vielen Runden zusammengesetzt und den Schnitt diskutiert. Aus diesen Diskussionen haben wir im Team eine Vision für einen neuen Softwareschnitt erarbeitet, die wir gemeinsam in einem Experiment erproben wollten. Schließlich konnten wir im Vorhinein nicht wissen, ob unsere neue Idee wirklich besser war. Unsere Idee war die Gesamtverantwortung für ein neues Produkt nicht wie vorher zu verteilen, sondern zentral in die Hand unseres Teams zu geben. So gab es kaum Abhängigkeiten nach außen, bis auf allgemeine, für alle Produkte notwendigen Funktionen. Daraufhin haben wir uns als Entwickler*innen zusammengesetzt, um zu entscheiden, wie wir unsere Software schneiden wollten.
Wir haben uns dafür entschieden, erstmal mit einem modularen Monolithen zu starten. So hatten wir innerhalb des Monolithen eine saubere Trennung der fachlichen Verantwortlichkeiten und konnten leichter reagieren, wenn wir festgestellt haben, dass wir die Module falsch geschnitten haben. Aufsplitten könnten wir den Monolithen durch seine Modularität immer noch, wenn er eine Komplexität erreicht hat, die für uns nicht mehr zu handlen wäre.
Nach etwa einem halben Jahr kann ich sagen, dass sich unsere Vorgehensweise und Initiative wirklich bezahlt gemacht hat. Der neue Schnitt hat zu viel mehr Autonomie in unserem Team geführt. Hierdurch sind wir viel schneller geworden als wir es im alten Produkt je waren. Diese gesteigerte Geschwindigkeit und die neu erlangte Autonomie haben in unserem Team die Stimmung wieder erheblich verbessert, sodass wir seither optimistisch in die Zukunft schauen. Ich bin auf jeden Fall gespannt, ob wir unseren Monolithen so leicht wie gedacht aufbrechen können, wenn er zu mächtig wird. Aber das wird die Zukunft zeigen.
Technische Schulden
Eine andere Herausforderung, die mich (und sicherlich auch viele von euch) bei fast jedem Projekt beschäftigt, ist das Thema technische Schulden. Da wir die Software von Grund auf geschrieben haben, sind wir zwar ohne Schulden gestartet, allerdings haben wir aus zwei Gründen schneller als erwartet technische Schulden aufgebaut.
Zum einen haben wir uns von Anfang an für den Livegang eine ambitionierte Deadline gesetzt, was dazu geführt hat, dass wir an einigen Stellen vertretbare Abstriche machen mussten. Meist typische Abkürzungen, wie zum Beispiel das Error Handling stark zu vereinfachen oder uns nicht die Zeit zu nehmen, um am Ende den Code nochmal gründlich zu reviewen und zu refactoren.
Zum anderen hatte keiner von uns zu Projektbeginn je mit Domain Driven Design und hexagonaler Architektur gearbeitet. Wir hatten lediglich theoretisches Wissen aus Büchern und Workshops hierzu. Dadurch haben wir unseren Code nicht nahe genug an der Fachlichkeit strukturiert. Oft fiel es uns auch schwer, die richtigen Stellen im Code zu finden, die wir anfassen mussten, um bestimmte fachliche oder regulatorische Anforderungen umzusetzen.
Auch mussten wir sehr oft mehr anpassen, als nötig wäre, wenn wir Fachlichkeit und Technik sauber voneinander getrennt hätten. Im Großen und Ganzen hat es sich so angefühlt, als ob wir den Mehraufwand der hexagonalen Architektur auf uns genommen hatten, aber ohne den Mehrwert daraus ziehen zu können.
Mir persönlich, wie den meisten Entwickler*innen, ist Software-Qualität aber ein zentrales Bedürfnis, weil es meine Arbeit erleichtert und auch den Spaß an der Entwicklung erhöht: Wer möchte denn schon mit schwer les- und wartbarem Code arbeiten?
Im Team haben wir uns Gedanken gemacht, wie wir das Thema am besten angehen und wir haben uns dafür entschieden, iterativ vorzugehen. Zuerst haben alle Entwickelnden die Hausaufgabe bekommen, alle technischen Schulden, die bei der täglichen Arbeit stören oder die Wartung und den Betrieb erschweren, in Jira zu erfassen. Und siehe da: ⅓ unseres Backlogs bestand nun aus technischen Schulden-Tickets. Der Missstand war also transparent und offensichtlich.
Zwei Dinge waren uns in der Behebung des Problems vor allem wichtig: Wir wollten nicht aufhören, Kundenmehrwert zu liefern, weshalb wir parallel zum „normalen” Doing Schulden abbauen mussten. Außerdem hilft es nichts, nur jetzt Schulden abzubauen, wo wir sowieso schon zu viel angesammelt haben. Stattdessen brauchen wir immer den Raum, um technische Schulden abzubauen, damit die Software in gutem Zustand bleibt. Zusammen mit unserer PO haben wir uns darauf geeinigt, dass wir jeden Sprint eine Kapazität von etwa 10 % investieren, um Schulden abzubauen. Auf diese Weise konnten wir unsere Software kontinuierlich verbessern. Was wichtig und was dringend ist und wie unsere Vision für den Code ist, besprechen und entscheiden wir als Entwickler*innen kollektiv gemeinsam jede Woche neu. Größeres Refactoring machen wir im Mob, um das für uns bestmögliche Ergebnis zu erzielen.
Nachdem wir diesem Vorgehen seit fast einem Jahr folgen, hat sich die Qualität unserer Software extrem verbessert. Über die Diskussionen und die Zeit zum Refactoren haben wir jetzt eine hexagonale Architektur, die robust ist und uns schnelle Änderungen ermöglicht. Unser Logging und Fehlerhandling erlauben schnelle Problemanalyse und Lösungen, sodass wir die Zeit, die den Abbau von technischen Schulden gekostet hat, längst wiedergewonnen haben. Außerdem, und das ist noch wichtiger als der Abbau selbst, haben wir dadurch eine Awareness für Software-Qualität bei Entwickler*innen, Fach- und Projektverantwortlichen geschaffen, die lange nachwirken wird. Das freut mich, da meine Tätigkeit so eine Wirkung entfalten wird, selbst nachdem ich das Projekt verlassen habe.
Ein persönliches Erfolgserlebnis war für mich, dass unsere PO uns in einem Sprint erinnert hatte, noch technische Schulden-Tickets in den Sprint zu nehmen, weil wir Entwickler*innen das vergessen hatten. Dies hat mir gezeigt: Die vielen Diskussionen und das gemeinsame Arbeiten haben sich gelohnt!
Was nehme ich aus dem Projekt mit?
In der Beratung geht nun mal jedes Projekt zu Ende. Auch ich werde weiterziehen, um mich weiterentwickeln zu können, selbst wenn ich die Arbeit im Projekt sehr genieße. Aber was werde ich eines Tages aus der Nachbetrachtung der Projektzeit für mich persönlich und für codecentric ziehen?
Worauf ich definitiv in der Zukunft mehr achten werde, ist, dass gute Software nur durch einen Prozess mit konstanten Diskussionen und Refactoring entstehen kann. „Life is refactoring”, wie ein Kollege vom Kunden zu sagen pflegt. Wo ich kann, werde ich meinen Kolleg*innen dazu raten, auch den Code zu diskutieren, technische Schulden zu erfassen und Zeit für Optimierungen einzufordern. Mir persönlich hat der Modus mit kleinen Optimierungen jeden Sprint sehr gut gefallen und ich werde versuchen, so einen Modus auch in künftigen Projekten zu etablieren.
Richtung Domain Driven Design habe ich ebenfalls viel mitgenommen und auch dort werde ich genauer auf die Kontextschnitte schauen und vor allem darauf achten, dass wir zu Beginn eines Projekts nicht zu viel schneiden. Lieber ein bisschen länger ein bisschen größere Kontexte haben und dann später, wenn die Domäne greifbarer ist, refactoren und die Software neu schneiden.
Auch innerhalb des Kontexts werde ich versuchen, die Codebase spät zu splitten. Natürlich verlangt das Disziplin beim Entwickeln, sonst hat man den klassischen „Big Ball of Mud”, aber die Investition lohnt sich.
Was macht der Kunde in Zukunft anders?
Auch für den Kunden hat sich in meiner Projektzeit viel verändert und wir haben erfolgreich viele Sachen verbessert.
Ich denke in der Zukunft werden crossfunktionale Teams beim Kunden einen hohen Stellenwert haben. Wir haben in dem Projekt bewiesen, dass diese Arbeitsweise sowohl beschleunigt, als auch die Qualität der Lösung verbessert.
Außerdem denke ich, dass durch unsere Verprobung von Domain Driven Design das Verständnis beim Kunden für Softwareschnitte gewachsen ist und die Autonomie der Teams und Verteilung von Verantwortung einen höheren Stellenwert im Unternehmen haben wird.
Ich denke auch, dass die Awareness für Softwarequalität beim Kunden schärfer ist als noch zu Beginn des Projekts. Praktiken wie Test-Driven-Development oder Behavior-Testing sind nicht mehr nur gehörte Begriffe, sondern mittlerweile oft schon gelebte Praxis. Bei den Kolleg*innen unseres Teams ist das Verständnis für Software-Qualität und den Raum für Refactoring sehr gut ausgeprägt und ich denke, dass sowohl Fach-, als auch Softwarekolleg*innen durch die positiven Erfahrung für ihre zukünftige Karriere nachhaltig sensibilisiert sind.
Im Großen und Ganzen hoffe ich mit diesem Erfahrungsbericht vermitteln zu können, dass ich eine lehrreiche Zeit im Projekt hatte, Vieles lernen durfte und tolle Menschen kennengelernt habe.
Gemeinsam bessere Projekte umsetzen.
Wir helfen deinem Unternehmen.
Du stehst vor einer großen IT-Herausforderung? Wir sorgen für eine maßgeschneiderte Unterstützung. Informiere dich jetzt.
Hilf uns, noch besser zu werden.
Wir sind immer auf der Suche nach neuen Talenten. Auch für dich ist die passende Stelle dabei.
Leonid Kiritschenko
Senior Development Consultant
Möchtest du mehr erfahren?