andregoepel.dev
Gespräch anfragen
Alle Artikel
Softwarearchitektur 5 Min. Lesezeit

Architektur im laufenden Betrieb korrigieren: Lehren aus einem mehrjährigen Plattformprojekt

Wer eine Plattform über mehrere Jahre begleitet, erlebt auch die Folgen früherer Architekturentscheidungen. Manche tragen länger als erwartet. Andere erzeugen unter realer Last Arbeit, die anfangs kaum sichtbar war. In einem langjährigen Projekt habe ich solche Grenzen analysiert und Korrekturen mit vorangetrieben. Die Umsetzung war Teamarbeit. Hier geht es darum, was sich daraus für den nächsten Umbau lernen lässt.

.NETSoftware ArchitectureModernizationLegacy Systems

Der Betrieb liefert neue Erkenntnisse

In einem mehrjährigen Plattformprojekt gehörte es zu meiner Arbeit, technische Probleme über längere Zeit zu verfolgen. Die Anwendung nahm Daten aus unterschiedlichen Quellen auf, verarbeitete sie und stellte sie für die weitere Nutzung bereit.

Mit wachsender Nutzung wurden Grenzen sichtbar, die sich in einer kontrollierten Umgebung schwer beurteilen ließen: zusätzlicher Aufwand bei Deployments, schwierige Fehlersuche über mehrere Komponenten hinweg und eine Datenaufnahme, die auf Verbindungsprobleme empfindlich reagierte.

Solche Beobachtungen sind zunächst Hinweise. Aus einer langsamen Anfrage folgt noch kein Architekturprojekt. Interessant wird es, wenn dieselbe Art von Problem wiederkehrt und lokale Reparaturen den Aufwand nur verschieben.

Erste Korrektur: Services wieder zusammenführen

Die Plattform war früh in Microservices aufgeteilt worden. Im Betrieb entstanden dadurch zusätzliche Abstimmungen bei der Bereitstellung, Latenzen zwischen Diensten und mehr Aufwand bei der Diagnose. Die Vorteile einer unabhängigen Skalierung rechtfertigten diese Kosten in der damaligen Ausprägung nicht ausreichend.

Wir führten die Plattform deshalb in einem modularen Monolithen zusammen. Die Deployments wurden einfacher, die Fehlersuche direkter und das Laufzeitverhalten besser vorhersehbar.

Das war eine Korrektur für diese Plattform. Daraus würde ich keine allgemeine Absage an Microservices ableiten. Relevant war, welche Unabhängigkeit die vorhandene Aufteilung tatsächlich ermöglichte und was sie im Alltag kostete.

Meine Lehre daraus: Eine bestehende Grenze sollte ihren Zweck erklären können. Wenn zwei Komponenten ohnehin gemeinsam geändert, getestet und veröffentlicht werden müssen, lohnt sich die Frage, welchen Nutzen ihre getrennte Bereitstellung noch hat.

Auch nach dem Zusammenführen bleiben fachliche Grenzen wichtig. Weniger Prozesse ersetzen keine Zuständigkeiten im Code und bei den Daten.

Zweite Korrektur: Datenaufnahme und Verarbeitung entkoppeln

Ein anderer Problembereich war die Datenaufnahme aus unterschiedlichen Umgebungen. Unter produktiver Last traten Verbindungsabbrüche und Timing-Probleme auf, die sich nur schwer reproduzieren ließen.

Wir stellten den Ablauf auf eine Verarbeitung mit persistierter Queue um. Die Stabilität verbesserte sich. Der wesentliche Unterschied: Annahme und weitere Verarbeitung waren nicht mehr in derselben Weise zeitlich voneinander abhängig.

Eine Queue kann eingehende Arbeit puffern und vorübergehende Lastspitzen abfangen. Wenn dauerhaft mehr Arbeit ankommt, als verarbeitet wird, wächst allerdings der Rückstand. Microsoft erläutert diesen Zusammenhang im Queue-Based-Load-Leveling-Muster.

Für einen solchen Umbau würde ich deshalb neben dem Normalfall ausdrücklich die Wiederholung betrachten: Was passiert, wenn derselbe Auftrag noch einmal verarbeitet wird? Wie werden dauerhaft fehlerhafte Aufträge sichtbar? Ab welchem Rückstand muss jemand eingreifen?

Die Queue ist ein technischer Baustein. Ob der Geschäftsprozess damit robuster wird, hängt auch von diesen Antworten ab.

Eine weitere Erkenntnis: Jede Schicht braucht einen Zweck

Im damaligen Projektstand war außerdem die Vereinfachung stark genutzter Importpfade ein weiteres Arbeitsfeld. Zusätzliche API-Schichten erzeugten dort Umwege und erschwerten die Zuordnung von Datenverantwortung. Diesen Punkt beschreibe ich bewusst als damalige Arbeit am System, nicht als inzwischen belegten dritten Abschlusserfolg.

Die Frage dahinter ist auch unabhängig vom Projekt nützlich: Welche Aufgabe erfüllt eine Schicht heute?

Sie kann Zugriffe kontrollieren, Geschäftsregeln bündeln oder einen stabilen Vertrag für andere Komponenten bereitstellen. Solche Aufgaben verschwinden nicht, wenn man die Schicht entfernt. Ein direkterer Zugriff ist nur dann eine Verbesserung, wenn die benötigten Regeln und Verantwortlichkeiten weiterhin klar verankert sind.

Wie ich einen solchen Umbau heute strukturieren würde

Die folgenden Schritte sind meine Empfehlung für vergleichbare Vorhaben. Sie sind kein nachträglich rekonstruiertes Ablaufprotokoll des beschriebenen Projekts.

1. Einen beobachtbaren Fehler zum Ausgangspunkt machen

„Die Architektur ist zu kompliziert“ reicht nicht. Ein brauchbarer Ausgangspunkt wäre: Nach einer Verbindungsunterbrechung bleiben Importaufträge liegen und müssen manuell nachbearbeitet werden.

Damit lässt sich ein Ziel beschreiben. Beispielsweise soll ein bestimmter Fehlerfall kontrolliert wieder aufgenommen werden können. Erst danach würde ich über das technische Mittel entscheiden.

2. Den kleinsten sinnvollen Bereich verändern

Ein Importweg, eine Modulgrenze oder ein Bereitstellungsschritt kann für die erste Korrektur reichen. Die Änderung sollte groß genug sein, das Problem zu lösen, und klein genug, ihre Wirkung zu verstehen.

Für größere Ablösungen beschreibt das Strangler-Fig-Muster einen schrittweisen Übergang, bei dem alte und neue Funktionalität zeitweise nebeneinander bestehen. Das ist eine mögliche Vorgehensweise; der hier geschilderte Case belegt nicht, dass genau dieses Muster eingesetzt wurde.

3. Vorab klären, was bei einem Fehlschlag passiert

Eine alte Anwendungsversion wieder zu starten genügt nicht immer. Hat der neue Weg bereits Daten verändert, müssen diese auch für den vorherigen Weg noch verwendbar sein oder gezielt korrigiert werden können.

Ich würde deshalb vor der Umstellung festhalten, wer sie stoppen darf, welche Zustände erhalten bleiben müssen und wie ein Fehler erkannt wird. Diese Fragen gehören zur Architekturentscheidung, nicht erst zur letzten Deployment-Besprechung.

4. Wirkung prüfen und den Übergang beenden

Nach der Änderung zählt das ursprüngliche Problem: Sind weniger manuelle Eingriffe nötig? Lassen sich Fehler schneller zuordnen? Hat sich der Engpass nur an eine andere Stelle verschoben?

Wenn der neue Weg trägt, braucht auch das Entfernen des alten einen Termin. Sonst muss das Team dauerhaft zwei Varianten verstehen und pflegen.

Was über mehrere Jahre wertvoll wird

Mein wichtigster Beitrag war nicht ein einzelnes Architekturdiagramm. Es war, das System lange genug zu kennen, wiederkehrende Probleme einzuordnen und mit dem Team tragfähige Korrekturen zu entwickeln.

Eine Entscheidung darf später geändert werden. Entscheidend ist, dass die neuen Erkenntnisse nachvollziehbar sind und der Übergang für die Menschen beherrschbar bleibt, die die Plattform weiterentwickeln und betreiben.

Muss eure Plattform weiterlaufen, während ihr sie verändert?

Ich unterstütze Unternehmen dabei, gewachsene .NET-Anwendungen zu analysieren und Modernisierung in überschaubare Schritte zu zerlegen. Im kostenlosen Erstgespräch können wir besprechen, wo eure Plattform heute Aufwand verursacht und welcher erste Eingriff sinnvoll wäre.

Neue Artikel per E-Mail

Eine Mail pro Artikel. Kein Newsletter-Theater, keine Tracking-Pixel.

Abmeldung mit einem Klick. Keine Weitergabe.