
Wenn die Microservice-Wette nicht aufgeht
Microservices waren nie das Ziel. Das Ziel war unabhängige Skalierung und die Möglichkeit, dass viele Teams parallel und ohne Abstimmung arbeiten können. Der Service-Schnitt war das Mittel dazu, und für diese beiden Annahmen war er richtig.
Fünf bis acht Jahre später sieht die Lage in vielen Unternehmen anders aus. Die Last ist nie in der geplanten Höhe eingetroffen, und die Teams, für die geschnitten wurde, gibt es nicht mehr. Die Architektur steht trotzdem noch in voller Größe da.
Das ist der Punkt, an dem aus einer sinnvollen Entscheidung eine teure wird.
Zwei Annahmen, die nicht mehr tragen
Die Last ist nie gekommen
Ein neues Produkt entsteht auf der grünen Wiese. Die Erwartungen sind hoch, die Lastannahmen großzügig, das System wird für eine sechsstellige Nutzerzahl ausgelegt. Drei Jahre später ist ein Bruchteil davon erreicht. Genug, um das Produkt weiterzubetreiben, aber weit entfernt von der Zahl, die die Architektur begründet hat.
Was übrig bleibt, ist ein verteiltes System für eine Last, die jeder gut strukturierte Modulith ohne Mühe trägt:
Services, die mit einstelliger Auslastung laufen und trotzdem redundant bereitstehen
Cluster-Kosten für eine Skalierung, die nicht kommen wird
REST-Aufrufe, wo ein Methodenaufruf genügen würde
Eventual Consistency, wo eine Transaktion einfacher und verlässlicher wäre
Fehlersuche über mehrere Systeme hinweg, wo ein Stack-Trace gereicht hätte
Die Teams gibt es nicht mehr
Der zweite Grund für den feinteiligen Schnitt war organisatorisch. In der Aufbauphase arbeiten viele Teams parallel an viel neuer Fachlogik. Jedes Team bekommt seinen Service, seine Pipeline, seinen Release-Zyklus. Das reduziert Abstimmung und war so gedacht.
Nach der Aufbauphase ändert sich das Bild. Die Kernfunktionalität steht, es kommen weniger neue Anforderungen, Teams werden zusammengelegt oder verkleinert. Die Services bleiben getrennt. Plötzlich betreut ein Team drei oder fünf Services, die früher je einem eigenen Team gehörten.
Wenn ein Team drei Services pflegt, sind das keine drei Services mehr. Das ist ein Modulith mit unnötiger Netzwerk-Latenz.
Besonders deutlich wird das bei einem geplanten Scale-Down. Wenn ein Team schrumpft, schrumpft die Komplexität nicht mit. Die Fachlichkeit lässt sich kaum reduzieren, denn Kunden, Verträge, Prozesse und gesetzliche Anforderungen verschwinden nicht, nur weil weniger Köpfe da sind. An der Technik dagegen gibt es echte Hebel. Nur muss man sie ziehen, solange das Wissen und die Kapazität dafür noch im Haus sind.
Was der Zustand kostet
Die Kosten stehen selten an einer Stelle, deshalb fallen sie lange nicht auf.
Auf der Cloud-Rechnung. Wenn Kosten zum Thema werden, beginnen viele bei FinOps: kleinere Instanzen, Rabatte, ungenutzte Ressourcen abschalten. Das ist sinnvoll, es optimiert aber vor allem die bestehende Struktur. Die größere Frage lautet, welche dieser Kosten überhaupt noch existieren müssten. Bezahlt werden nicht nur Rechenzeit, sondern doppelte Datenhaltung, zu fein geschnittene Services und zusätzliche Kommunikationsschichten.
Im Betrieb. Jede Infrastrukturkomponente bringt einen eigenen Lifecycle mit: Updates, Sicherheitslücken, Lizenzen, Monitoring, Bereitschaft. Drei Message Broker, fünf Datenbanken in vier Varianten und ein Service Mesh für sieben Services summieren sich zu einem Aufwand, den niemand als einzelne Position bemerkt.
In der Fehlersuche. Was in einer einzigen Anwendung ein NullPointer war, ist im verteilten System ein verlorenes Event, ein Retry-Loop oder ein partieller Schreibvorgang über drei Datenbanken. Debugging dauert Tage statt Stunden.
Bei der Technologievielfalt. Wenn jedes Team seinen Stack frei wählt, klingt das nach Autonomie. Im Betrieb entsteht daraus ein Zoo aus eigenen Pipelines, eigenem Tooling und eigenen Security-Patches. Onboarding dauert länger, gegenseitige Unterstützung zwischen Teams wird schwerer, und das Zusammenführen zweier fachlich verwandter Services wird unnötig aufwändig.
Im Team. Der teuerste Effekt taucht in keiner Rechnung auf. Das Team verbringt mehr Zeit mit Verwalten als mit Bauen. Neue Anforderungen werden nicht abgelehnt, sondern verzögert, bis sie irrelevant sind.
Warum "wir schreiben das neu" die falsche Antwort ist
An diesem Punkt liegt die Neuentwicklung nahe. Sie übersieht nur, was in dem System steckt: hunderte Sonderfälle, Workarounds und fachliche Regeln, die nirgends dokumentiert sind. Das ist kein Ballast, sondern kondensierte Geschäftslogik, die sich über Jahre unter realen Bedingungen bewährt hat.
Wer bei Null anfängt, muss all das erneut entdecken. In der Zwischenzeit läuft das alte System weiter und wird weiter gepflegt. Nach drei Jahren steht ein zweites Legacy-System, mit weniger fachlichem Wissen als das erste.
Der Rückbau geht den anderen Weg. Er erkennt an, was funktioniert, und entfernt gezielt, was im Weg steht.
Der Weg zurück, in vier Schritten
1. Bewertung
Zuerst braucht es ein ehrliches Bild: Wie viele Nutzer und Transaktionen laufen tatsächlich durch das System, und wie viel davon war beim Schnitt angenommen? Welche Services laufen dauerhaft bei drei Prozent Last? Welche Komponenten kosten wie viel an Lizenz, Betrieb und Bereitschaft? Wie viele Services müssen in fester Reihenfolge deployed werden?
Diese Fragen kann ein Team auch selbst stellen. In der Praxis passiert es selten, weil die gewachsene Komplexität im Alltag normal geworden ist. Wenn ein Release fünf Services in fester Reihenfolge braucht, heißt das intern "unser Ablauf". Von außen heißt es verteilter Monolith.
2. Zielbild
Eine Bewertung ohne Zielbild produziert nur eine Mängelliste. Das Zielbild beantwortet, welche Bounded Contexts es wirklich gibt, welcher Schnitt zur heutigen Organisation passt und welche Infrastruktur bleibt.
Die Beweislast dreht sich dabei um: Ein verteiltes System braucht einen belegbaren Grund. Unabhängige Skalierung um ein Vielfaches, organisatorische Trennung oder regulatorische Auflagen sind solche Gründe. "Haben wir damals so eingeführt" ist keiner.
3. Absicherung durch Tests
Modernisierung ohne Tests ist ein Umbau ohne Gerüst. Bevor Code bewegt wird, muss das bestehende Verhalten abgesichert sein. Nicht perfekt, aber ausreichend, um Regressionen zu erkennen.
Charakterisierungstests beschreiben dafür nicht das gewünschte, sondern das tatsächliche Verhalten, inklusive der Eigenheiten aus zehn Jahren Betrieb. Dazu kommen Integrationstests an den Systemgrenzen und eine Testinfrastruktur mit kurzen Feedback-Zyklen. Tests, die eine halbe Stunde laufen, werden nicht genutzt.
Zwei Punkte entscheiden über den Aufwand. Abgesichert wird zuerst, was als Nächstes geändert wird, nicht das gesamte System. Und bestehende fragile Tests werden repariert oder entfernt, denn ein Test, der ignoriert wird, untergräbt das Vertrauen in die gesamte Suite.
Diese Phase ist durch Coding-Agenten deutlich schneller geworden. Ein Agent liest den bestehenden Code, erschließt das Verhalten systematisch und liefert Testentwürfe. Die Bewertung bleibt beim Entwickler, die Fleißarbeit nicht.
4. Rückbau und Konsolidierung
Erst wenn die Absicherung steht, beginnt der Umbau. Ein häufiger erster Schritt ist Konsistenz: In vielen Systemen liegen mehrere Architekturstile nebeneinander, Reste angefangener Modernisierungen. Bevor neue Strukturen entstehen, muss klar sein, welchem Muster der Code folgt. Halbfertige Refactorings werden zu Ende gebracht oder bewusst zurückgerollt.
Danach greifen mehrere Hebel, je nach Ausgangslage:
Infrastruktur prüfen. Jede Komponente muss ihren Nutzen heute belegen. Ein Event, das nie ein zweiter Konsument liest, ist kein Event, sondern ein Methodenaufruf mit Betriebskosten. Ein Cache, der einen fehlenden Index kaschiert, ist eine zweite Quelle der Wahrheit mit eigenen Konsistenzproblemen.
Stack vereinheitlichen. Ein gemeinsames Ökosystem, ein gemeinsames Repository, ein Code Style. Das senkt den Aufwand in Pipelines, bei Updates und im Onboarding, und es ist die Voraussetzung dafür, Services überhaupt zusammenführen zu können.
Services zusammenführen. Zuerst die, die ein Team gemeinsam betreut, die immer gemeinsam deployed werden oder die auf denselben Daten arbeiten. Aus REST-Aufrufen werden Methodenaufrufe, aus zwei Datenbanken mit Synchronisation wird eine Datenbank mit einer Transaktion, aus verteilten Fehlerbildern werden lokale Stack-Traces.
Datenhaltung konsolidieren. Daten, die in einer Datenbank leben können, gehören in eine Datenbank. Eine Transaktion statt Synchronisation bedeutet weniger Inkonsistenzen und einfachere Backups.
Die fachliche Trennung bleibt
Der häufigste Einwand gegen den Modulithen ist die Sorge vor der großen Kugel Schlamm. Sie ist berechtigt, wenn im Modulithen keine Grenzen gezogen werden. Genau darum geht es aber beim Rückbau: Was vorher Service-Grenze war, wird Modulgrenze, durchgesetzt durch Spring Modulith, Paketstrukturen oder ArchUnit.
Entscheidend ist, woran diese Grenzen entlanglaufen. Ein Bounded Context sollte im Code
als kompakte Einheit erkennbar sein, nicht verteilt über zwanzig Pakete und erst recht
nicht zusammen mit zehn anderen Contexts in einer großen technischen Paketstruktur.
Wenn ein Repository vor allem application, domain, infrastructure und adapter
zeigt, wird technisch sortiert, wo fachlich geschnitten werden müsste.
Kohäsion entsteht entlang der Fachlichkeit, nicht entlang von Pattern-Namen. Das hilft neuen Teammitgliedern, die einen Zusammenhang an einer Stelle finden. Und es hilft KI-gestützten Werkzeugen, die mit klar abgegrenzten fachlichen Einheiten und kleinerem Kontext deutlich verlässlichere Ergebnisse liefern.
Was am Ende dabei herauskommt
Nach dem Umbau sieht das System nicht moderner aus, sondern angemessen:
weniger Services, Datenbanken und Infrastrukturkomponenten, mit messbar gesunkenen Betriebskosten
Deployments, die wieder ein einzelner Vorgang sind statt einer Choreografie
eine Codebasis, in der neue Entwickler nach zwei Wochen produktiv sind statt nach drei Monaten
Tests, auf die sich das Team verlässt und die jeden weiteren Umbau absichern
Kapazität, die nicht mehr ins Verwalten fließt, sondern in neue Aufgaben
Die Konsolidierung in einen Modulithen ist kein Rückschritt in die Zeit vor zehn Jahren. Sie ist die ehrliche Antwort auf die Frage, welche Komplexität die heutige Last und die heutige Team-Größe rechtfertigen.
Und für den nächsten Neubau bleibt eine brauchbare Faustregel: mit wenigen Services und klaren Modulen starten, und erst dann aufteilen, wenn ein konkreter Auslöser da ist. Nicht, weil er für übermorgen erwartet wird.
Nächster Schritt
Sie erkennen Ihr System in Teilen wieder? Eine Bewertung mit Zielbild dauert je nach Größe drei bis zehn Tage und liefert eine Entscheidungsgrundlage, mit der sowohl Entwicklung als auch Management arbeiten können. Schreiben Sie mir, dann schauen wir gemeinsam darauf.
Antworten auf die häufigsten Fragen zu Ablauf, Dauer, Kosten und Vorgehen stehen in den häufigen Fragen.