Ein frei erfundenes Unternehmen mit einer ganz typischen Software – über lange Jahre ständig weiterentwickelt, in der Regel unter Zeit- und Budgetdruck. Ein kleiner, aber fachlich komplexer Produktkatalog, ein großer Bestand von Endkunden, deren Bestellungen und Rechnungen wir in unserem System verarbeiten und anzeigen müssen. Ein bisschen Java, etwas relationale Datenbank, eine Portion SQL. Die ein oder andere kleine Sünde im System, nichts Besonderes – dachte ich immer.
Aber mal von Anfang an: Vor drei Jahren bin ich als Neuzugang zu unserem Team gestoßen. Vorher hatte ich einige Jahre Webshops und Java-Backends für eine kleine Firma gebaut, dann bin ich zu diesem großen und seriösen Unternehmen gewechselt und durfte direkt am Kernsystem mitarbeiten.
Mit was für schicken Sachen haben die damals um sich geworfen: Scrum und Kanban, polyglotte Entwicklung, attraktive Technologie und unternehmenskritische Anwendung. Alles wahr, aber einige Details habe ich erst später leidvoll erfahren müssen. Ich versuche mal eine Kurzbeschreibung: Eigentlich sollte das System drei Schichten haben …
Datenchaos
Aber schon unsere Datenhaltung nervt: Die meisten Daten liegen in ca. dreißig Tabellen in einer relationalen Datenbank. Leider haben wir vor zehn Jahren eine Firma übernommen, deren Datenbestand von einer AS/400 stammt: Die hatten sämtliche Stamm- und Produktionsdaten in einer netzartigen Struktur abgebildet: fünf Tabellen mit jeweils 400 Spalten, massiv über Kreuz vernetzt. Wir wollten das immer mal auf unser Datenmodell migrieren, hatten bisher aber keine Zeit dazu.
Die Daten von den fast 300 000 Altkunden müssen wir über den Umweg dieser grausamen Struktur lesen und schreiben. Bei jedem Zugriff auf Kundendaten müssen wir jetzt differenzieren, ob der Kunde im alten oder neuen Bestand liegt – und mit jeweils anderer Zugriffslogik bearbeiten. Welche Kunden wo liegen, entscheidet übrigens eine eigene Konfig-Tabelle in der neuen Datenbank (Abb. 1).
Und dann war da noch das optische Archiv, in das sich – leider fehlerhafte – Dokumente eingeschlichen haben, die man aber nicht mehr löschen kann oder darf. Das Altsystem liest Teile seiner Daten aus diesem Archiv, und muss dann jeweils in einer Blacklist-Tabelle nachprüfen, ob diese speziellen Datensätze bekannte Fehler enthalten – welch ein unglaublicher Mist.
Von wegen Businesslogik
Einige Teile unserer Businesslogik stecken brav in einem einzigen Package, lauter POJOs mit Spring, übersichtlich und gut verständlich. Leider liegen die meisten Geschäftsregeln und -services nahezu beliebig verstreut in alten Systemteilen, manche davon in Perl, C, C++ oder sogar XSLT geschrieben (wobei „verbrochen“ der treffende Begriff wäre).
Es verfault von innen
Eine Kernaufgabe unseres Systems ist die Ermittlung von Preisen für Angebote und Waren. Stellen Sie sich vereinfacht vor, Kunden haben einen komplexen Warenkorb, mit aufwändig konfigurierten Produkten drin. Unsere Pricing Engine prüft nun Firmen- und Einzelrabatte, Sondervereinbarungen, Mindest- und Höchstmengen, Sonderregelungen für Produktkombinationen und allerhand weitere Bedingungen, um daraus einen Gesamtpreis zu berechnen. Das hat vor langer Zeit ein hoch motivierter (Ex-)Mitarbeiter in Haskell implementiert – rein funktional, zustandslos und recht performant, damals zumindest. Der Kollege hat vor zwei Jahren unsere Firma verlassen – und kein anderer hat bisher den dafür nötigen Haskell-Guru-Status erreicht: Wir verstehen seinen Code in großen Teilen nicht. Funktoren, Monaden und teilweise 10- bis 15-fach geschachtelte Funktionsaufrufe … Insgesamt mehr als 20 000 Zeilen, die jeden aufsaugen, der zu lange im Editor draufschaut. Niemand traut sich wirklich, darin etwas zu ändern, Tests sind aufgrund der ständig wechselnden Preis- und Rabattmodelle total schwierig zu bauen – und „neu schreiben“ hat uns das Management verboten. Ein echtes schwarzes Loch, diese Komponente.
View-Pipeline
Das ursprüngliche Entwicklungsteam hat damals auf Apache Cocoon als Mechanismus zur Erzeugung des Ausgabe-HTMLs gesetzt: Ein modularer Pipes-und Filterarchitekturstil, ein renommiertes Open-Source-Projekt, da sollte doch nichts schief gehen können: Weit gefehlt. Unser damaliges Management hat diese View-Pipeline für einige Jahre an einen ausländischen Dienstleister „outgesourced“ (welch ein Wort) – und ist daran gescheitert. Dieses Subsystem kam nach der Auflösung des Outsourcing-Vertrags zur Weiterentwicklung in die Hände unseres Inhouse-Teams zurück – war allerdings kaum wiederzuerkennen: Modularität, Separation of Concern und Entkopplung hatte das externe Team gründlich wegoptimiert.
Die fremden Entwickler haben Rendering- und Businessfunktionen massiv vermischt, d. h. während der Generierung von HTML-Seiten werden viele Businessregeln und -prozesse ausgeführt, und zwar in XSLT-Skripten. Zigtausende Zeilen unwartbarer Code, eine krude Mischung aus Templating, Datentransformation und Ablaufsteuerung. Stellen Sie sich vor – die View-Pipeline ändert (!) Produktivdaten (Abb. 2). Ziemlich genau das Gegenteil von „Separation of Concern“.
Meine kleine Tochter ruft an – ob ich wenigstens heute mal pünktlich nach Hause käme? Vor einem Jahr noch habe ich das fast immer geschafft. Jetzt haben wir derart viele Probleme, dass es meistens 19 Uhr oder später wird. Obwohl wir uns alle anstrengen, es wird einfach immer schwieriger und die Belastung für alle Entwickler immer höher.
Der Weg zur Besserung
In dieser Situation zu kapitulieren, kommt gar nicht in Frage. Unser Geschäftsmodell funktioniert, das Team ist klasse, und wir verstehen genug von Software Engineering, dass wir die Probleme in den Griff bekommen können. Wir, unser Team, haben uns entschieden, die Verbesserung systematisch anzugehen. Wir lassen uns von der (Open-Source-)Methodik aim42 (Architecture Improvement Method [1]) leiten. In aim42 stecken eine Menge bekannte und erprobte Good Practices drin, und vor allen Dingen können wir damit auch unsere (bisher) veränderungsresistenten Manager ansprechen.
Also – ans Werk: Wir trennen die Analyse, Bewertung und Behebung der Probleme sauber voneinander: Zuerst sammeln wir mal die bekannten Probleme in einer Issue-Liste [1]. Anschließend bewerten wir diese Probleme der Reihe nach aus betriebswirtschaftlicher (!) Sicht. Jetzt suchen wir für die „teuren“ Probleme nach Lösungs- oder Abhilfemaßnahmen – und schätzen auch die nach Aufwand oder Kosten ab.
Erstens: Probleme suchen und bewerten
Um alle Probleme zu finden, haben wir als erstes Stakeholder-Interviews durchgeführt. Uns als Entwicklungsteam ist natürlich klar, was wir selbst als Problem betrachten, aber das Management und der Product Owner sehen das vielleicht ganz anders. Durch die Stakeholder-Interviews haben wir noch den Punkt „Benutzerführung beim Abschluss des Einkaufs“ als weiteren Issue aufgenommen. Uns war nicht klar, dass die Benutzer Mühe haben, unser System im Bereich „Abschluss des Einkaufs“ zu benutzen. Für die Firma ist das aber ein essenzieller Moment. Alle Kunden, die hier abspringen, weil sie mit der Benutzerführung nicht klarkommen, sind ein sehr später und sehr teurer Verlust.
Aus den Stakeholder-Interviews sammeln wir zwei Punkte für unsere Issue-Liste. Außerdem kommen noch unsere eigenen Punkte hinzu (Tabelle 1).
In echten Verbesserungsprojekten umfassen solche Issue-Listen möglicherweise hunderte von Einträgen. Für diesen Artikel haben wir dramatisch gekürzt und zeigen nur ausgewählte Beispiele.
ID | Name | Beschreibung | Auftreten/Häufigkeit |
---|---|---|---|
1 | Benutzerführung | Beim Abschluss des Einkaufs im Warenkorb ist der Button „Verbindlich bestellen“ nur ganz unten am Ende der Seite zu finden. Das scheint viele Käufer zu irritieren. Außerdem kann man die Lieferadresse erst eingeben, nachdem man den Kauf abgeschlossen hat. Das ist sehr unüblich und führt zu vielen Rückfragen und vermutlich auch zu Absprüngen. | Schätzung: Jeder zehnte Einkäufer |
2 | Wartung | Erweiterungen am System dauern sehr viel länger als nötig und sind fehlerbehaftet. Die Teams können keinen Termin für die Fertigstellung eines neuen Features angeben. Das ist sehr unbefriedigend | Jede größere Erweiterung, die mehr als 10 PT umfasst |
3 | Altdaten | 300 000 Altkunden befinden sich in einer alten Datenbank und müssen über eine Weiche und eigene Logik angesprochen werden. | Bei jedem DB-Zugriff |
4 | Datenfehler | Im optischen Archiv existieren fehlerhafte Daten, die über eine Blacklist aussortiert werden. | Bei jedem Zugriff auf das optische Archiv |
5 | Geschäftsregeln | Teile der Geschäftsregeln sind im Altsystem (verschiedene Programmiersprachen) und in XLSTs programmiert. | |
6 | Pricing Engine | Das fachliche Herz des Systems ist in komplexer Haskell-Logik programmiert (noch kein Problem, aber ein Risiko). |
Eine Lektion aus aim42 lautet: Suchen Sie an unterschiedlichen Stellen nach Problemen – einige Möglichkeiten zeigen die in Abbildung 3 dargestellten Ansätze – ohne Anspruch auf Vollständigkeit (für mehr Details siehe [1]).
Hätten Außenstehende unser System analysiert, dann hätten sie alle dem Team bekannten Punkte in unserer Issue-Liste mithilfe dieser Ansätze identifizieren können. Sicherlich hätten wir dann gemeinsam eine ATAM-Analyse durchgeführt, begleitet von Daten- und Infrastrukturanalyse.
Bei der Suche nach Problemen müssen wir sehr aufpassen, nicht in die so genannte „Mikroskopfalle“ zu tappen: Stellen Sie sich eine Kleinstadt nach einem heftigen Wirbelsturm vor. Falls Sie dort mit einem Mikroskop auf die Suche nach Problemen gehen, werden Sie sicherlich fündig, aber nur auf einem sehr detaillierten Level. Den Überblick erhalten Sie nur dann, wenn Sie aus einer Vogelperspektive zuerst einmal ganzheitlich auf die Situation schauen – und von dort aus gezielte Detailanalysen mit Lupen und Mikroskopen anstellen. Den Standort oder den Betrachtungsgegenstand einer mikroskopischen Untersuchung sollten Sie grundsätzlich aus einer Übersichtsbetrachtung festlegen.
Zweitens: Maßnahmen vorschlagen und bewerten
Bei unseren Stakeholder-Interviews haben wir nicht nur Probleme erklärt bekommen, sondern auch bereits einiges an Lösungsvorschlägen. Diese haben wir in einer Improvement-Liste gesammelt und dabei genau darauf geachtet, dass jeder Lösungsvorschlag sich auf mindestens eines unserer Probleme aus der Issue-Liste (siehe oben) bezieht. Natürlich haben wir Entwickler auch selbst darüber nachgedacht, wie wir die Probleme beheben könnten und unsere Vorschläge in diese Improvement-Liste aufgenommen.
Die Sammlung von Problemen und Lösungsvorschlägen sind wir in einer Timebox von fünf Tagen angegangen. Danach kam ein für uns schwieriger Teil von aim42: Sowohl die Issues, als auch die Improvements abschätzen: Wie weh tut uns das Problem? Und was kostet uns eine Verbesserung? Schätzen fanden wir schwierig, insbesondere die Schätzung der „Problemkosten“. Ein kleiner Tipp aus aim42 hat uns dabei sehr geholfen: Schätze grundsätzlich immer in Intervallen! Wenn die Intervalle zu groß sind, dann brauchen wir vielleicht noch mehr Informationen, um etwas präzisere Aussagen zu möglichen Aufwänden treffen zu können. Tabelle 2 zeigt einige der Vorschläge, die wir gesammelt haben.
# | Improvement | Betrifft „Issue–ID“ | Aufwand |
---|---|---|---|
1 | Oberfläche benutzerfreundlicher machen | 1 | Wenige PT |
2 | Migration der Altdaten | 3, 2 | 100–300 PT |
3 | Neuprogrammierung der Pricing Engine | 6 | ??? |
4 | Refactoring der HTML-Erzeugung (und Isolierung der Geschäftsregeln) | 5 | |
5 | Aufräumen des optischen Archivs und Beseitigung der Blacklist | 4 | 100–150 PT |
Abbildung 4 zeigt ein etwas umfassenderes Bild über die Tätigkeiten, die zur Evaluierung gehören: Neben den Schätzungen auch Abhängigkeitsuntersuchungen, Priorisierung und das „Verkaufen“ der am meisten lohnenswerten Verbesserungen an die Brötchengeber (üblicherweise das Management …).
Wir haben beispielsweise festgestellt, dass sich niemand zutraut, den Ersatz für die Haskell Pricing Engine zu schätzen, weil deren interne Arbeitsweise völlig undokumentiert und unverstanden ist. Eine Zwischenmaßnahme war deren Nachdokumentation: Wir hoffen, danach eine plausible Aufwandsschätzung für die Neuentwicklung der Pricing Engine erstellen zu können. Den Aufwand für diese Dokumentation schätzen wir mit 2 bis 3 Wochen ein.
aim42 schlägt parallel zu den hier genannten Phasen der Verbesserung vor, einige Aktivitäten querschnittlich und kontinuierlich anzugehen. Auf diese Crosscutting-Aufgaben (u. a. Planung) geht dieser Artikel nicht weiter ein.
Drittens: Verbesserungen planen und durchführen
Auf Basis der Vorschläge aus unserer Improvement-Liste haben wir gemeinsam mit unserem Management eine Roadmap für die langfristige Verbesserung unseres Systems aufgestellt. Dabei haben wir technische und wirtschaftliche Interessen ausbalanciert: Weil wir ausdrücklich auch die Kosten von Problemen („Issue Cost“) abgeschätzt haben, erkennt das Management jetzt viel besser den Nutzen mancher Verbesserungsmaßnahmen. Insgesamt haben wir uns von einigen grundlegenden Prinzipien leiten lassen:
- Frühes Feedback zu Verbesserungen hilft, die Maßnahmen gezielter zu steuern.
- Prototypen der Verbesserungen schaffen Sicherheit, bevor wir uns ans „lebende Objekt“ wagen.
- Wir prüfen und testen nach jeder Veränderung. Damit stellen wir sicher, dass wir keine „Verschlimmbesserungen“ einführen.
- Immer und überall versuchen wir, systematisch Komplexität zu reduzieren. Wir haben beispielsweise eine große Menge alter und nicht mehr aktueller Dokumentationen gelöscht – weil diese mehr verwirrt als genützt hat.
- Wir kompensieren fehlende Fakten (Ziele, Anforderungen, Schätzungen, …) durch explizite, schriftliche Annahmen. Dadurch können wir besser mit anderen Beteiligten diskutieren.
Das Fazit für unser System: Mit höchster Priorität das Frontend überarbeiten, sodass wir das teure Problem (#1, jeder zehnte Kunden springt ab) möglichst schnell lösen können. Außerdem führen wir im Frontend eine Weiche ein, die auf dem Original des Systems oder einer (neuen, iterativ verbesserten) Kopie arbeiten kann. Dann können wir jedes unserer Probleme schrittweise anpacken und in Betrieb nehmen, sobald es stabil genug ist.
Für Verbesserungsmaßnahmen stehen uns viele Praktiken offen (Abb. 5). Je nachdem, ob wir bei den Prozessen oder beim Produkt ansetzen, uns mehr um konzeptionelle oder strukturelle Themen kümmern möchten, oder beispielsweise die Infrastruktur unserer Systeme optimieren möchten – Optionen gibt es genug.
Schlussbemerkung
Seit wir die Evolution unseres Systems derart systematisch angehen, komme ich wieder viel öfter pünktlich nach Hause, wir haben weniger Produktionsprobleme und im Entwicklungsteam deutlich weniger Stress. Meine Tochter hat gefragt, warum wir das nicht schon viel früher so gemacht hätten – ich wäre jetzt immer besser gelaunt … Darauf konnte ich ihr leider keine Antwort geben.
Wie lernen Sie systematisch verbessern?
Sie möchten auch systematisch verbessern? Einen Überblick über die wirklichen Probleme Ihres Systems, sinnvoll hergeleitete Verbesserungsmaßnahmen in nachvollziehbarer Priorisierung erhalten? Ihr Management von der Sinnhaftigkeit langfristig angelegter Verbesserungsmaßnahmen überzeugen, und unsere typischen IT- und Programmierprobleme in allgemein verständliche Argumente übersetzen? Die bereits zitierte Methode aim42 [1] hält eine Menge weiterer Hinweise in Form etablierter Praktiken und Vorgehensmuster für Sie bereit. Außerdem könnte das Advanced-Level-Modul IMPROVE des iSAQB e. V. als Vertiefung für Sie interessant sein. Sie können darin Ihr Wissen bezüglich Evolution, Migration und Verbesserung unabhängig von Domäne, Branche oder Technologie ausbauen und zukünftig auch auf Ihre eigenen Systeme anwenden.
Referenzen
-
aim42, http://aim42.org sowie https://aim42.github.io ↩