Zum Inhalt springen

Von Monolith zu Modulith: Der pragmatische Mittelweg

Von Monolith zu Modulith: Der pragmatische Mittelweg
Michael Jauk
· Competitive Edge

“Wir müssen auf Microservices migrieren.”

Diesen Satz hören wir regelmäßig. Meistens kommt er, nachdem ein Team zum dritten Mal festgestellt hat, dass eine Änderung in Modul A etwas in Modul C kaputt gemacht hat. Die Frustration ist berechtigt. Die Schlussfolgerung meistens nicht.

Microservices lösen ein Organisationsproblem, kein Codeproblem. Wer mit einem unstrukturierten Monolithen kämpft, bekommt durch Microservices keinen strukturierten Code - sondern einen unstrukturierten verteilten Code. Mit Netzwerk-Latenz, verteilten Transaktionen und einem Kubernetes-Cluster obendrauf.

Es gibt einen Mittelweg. Einen, der in der Praxis für die meisten Teams besser funktioniert als beide Extreme.

Was ist ein Modulith?

Ein Modulith (Modular Monolith) ist eine Anwendung, die als eine Einheit deployed wird - aber intern in klar abgegrenzte Module aufgeteilt ist. Jedes Modul kapselt seine eigene Domänenlogik, Services und Infrastruktur. Die Kommunikation zwischen Modulen läuft über definierte Schnittstellen, nicht über direkte Zugriffe auf interne Klassen.

Der entscheidende Unterschied zum klassischen Monolithen: Beim Modulith sind die Grenzen erzwungen. Nicht durch Konventionen in einem Wiki, die nach drei Wochen ignoriert werden. Sondern durch Tooling, das den Build fehlschlagen lässt, wenn ein Modul auf die Interna eines anderen zugreift.

Der Unterschied zu Microservices: Die Grenzen werden im Prozess erzwungen, nicht über das Netzwerk. Das spart die gesamte Komplexität verteilter Systeme - Service Discovery, API Gateways, verteiltes Tracing, Circuit Breaker, Eventually Consistency.

MonolithModulithMicroservices
DeploymentEine EinheitEine EinheitUnabhängig pro Service
CodestrukturLayer-basiertDomänen-basiertDomänen-basiert
GrenzenKeine oder schwachErzwungen (Build-Zeit)Erzwungen (Netzwerk)
KommunikationAlles ruft allesÖffentliche APIs/EventsHTTP/gRPC/Messaging
DatenhoheitAlles geteiltSchema pro ModulDB pro Service
Ops-KomplexitätNiedrigNiedrigHoch
Refactoring-KostenNiedrigNiedrigHoch

Wann ein Modulith die bessere Wahl ist

Es gibt eine einfache Faustregel nach Teamgröße:

  • 1-10 Entwickler: Monolith, aber von Tag eins modular strukturiert
  • 10-50 Entwickler: Modulith. Struktur ohne Verteilungskomplexität
  • 50+ Entwickler: Selektive Microservice-Extraktion - dort, wo es sich nachweislich lohnt

In der Praxis liegt der Schwellenwert bei etwa 15-20 Entwicklern. Darunter übersteigt der Koordinationsaufwand von Microservices fast immer den Nutzen.

Konkretere Entscheidungskriterien:

Modulith wählen, wenn:

  • Die Domäne noch in Bewegung ist. Grenzen sind im selben Prozess einfacher zu verschieben als über Service-Grenzen hinweg.
  • Das Team unter 30 Entwicklern liegt und Koordination billig ist.
  • Kein Modul fundamental andere Skalierungsanforderungen hat als die anderen.
  • Die DevOps-Infrastruktur noch nicht für verteilte Systeme ausgelegt ist.

Microservices in Betracht ziehen, wenn:

  • Mehrere Teams sich gegenseitig beim Deployment blockieren.
  • Einzelne Module 10x mehr Ressourcen brauchen als der Rest.
  • Compliance explizit Service-Level-Isolation verlangt (PCI DSS, HIPAA).
  • Die Domäne stabil ist und die Grenzen erprobt.

Teams, die zuerst modular bauen und erst dann selektiv extrahieren, berichten von rund 30% höherer Feature-Velocity im Vergleich zu Teams, die direkt mit Microservices starten.

Migration in 5 Phasen

Phase 1: Domain Discovery (Monat 0-2)

Bevor Code angefasst wird: Domänen kartieren. Mit Produktexperten und Entwicklern gemeinsam. Welcher Code gehört zu welcher Business-Capability? Wo ändern sich Dinge häufig, wo ist es stabil?

Domain-Driven Design ist hier kein akademisches Framework, sondern ein praktisches Werkzeug. Bounded Contexts identifizieren heißt: Herausfinden, wo die natürlichen Bruchlinien im System liegen.

Phase 2: Modularisierung (Monat 2-6)

Das ist die eigentliche Arbeit:

  1. Packagestruktur umbauen - Weg von controller/service/repository, hin zu orders/shipping/billing. Domänen statt Layer.
  2. Öffentliche Interfaces definieren - Jedes Modul bekommt eine Fassade. Direkte Zugriffe auf interne Klassen werden verboten.
  3. Grenzen mit Tooling erzwingen - Packwerk (Ruby), ArchUnit (Java), dependency-cruiser (JS/TS). CI-Pipeline schlägt fehl bei Verletzungen.
  4. Infrastruktur an den Modulrand schieben - Domänenlogik bleibt rein. Datenbank-Zugriffe, externe APIs und Messaging gehören in die Infrastrukturschicht des jeweiligen Moduls.
  5. Modul-Integrationstests schreiben - Bevor irgendetwas extrahiert wird.

Phase 3: Erste Extraktion (Monat 6-8, nur wenn nötig)

Ein kleines, klar abgegrenztes Modul wählen. Auth oder Notifications sind typische erste Kandidaten. Feature Flags für den Rollout. Shadow Traffic zum Vergleich von altem und neuem Verhalten.

Phase 4: Weitere Extraktionen (Monat 9-12, nur wenn gerechtfertigt)

Nur dort, wo Daten, Skalierung oder Team-Ownership es klar rechtfertigen.

Phase 5: Betrieb und Evaluation (ab Monat 13)

Die meisten Module bleiben im Monolithen. Und das ist das richtige Ergebnis. Entscheidungen auf Basis von Evidenz, nicht auf Basis von Ideologie.

Datenisolation: Der unterschätzte Faktor

Einer der häufigsten Fehler bei der Modularisierung: Alle Module teilen sich weiterhin dieselben Datenbanktabellen. Das untergräbt jede Grenze.

Vier Stufen der Datenisolation, vom einfachsten zum stärksten:

Geteilte Tabellen - Alle Module nutzen ein Schema. Nur Konvention trennt die Zugriffe. Für den Anfang akzeptabel, aber fragil.

Schema pro Modul (unsere Empfehlung) - Jedes Modul hat sein eigenes Schema in derselben Datenbank. Module dürfen nur auf ihre eigenen Tabellen zugreifen. Cross-Modul-Zugriff nur über die öffentliche API, nie über direkte Queries.

Datenbank pro Modul - Höchste Isolation, aber auch höchster operativer Aufwand. Sinnvoll bei Compliance-Anforderungen oder wenn die Extraktion zum Microservice absehbar ist.

Domain Events - Module publizieren Events bei Zustandsänderungen. Andere Module pflegen lokale Read-Models. Eventual Consistency - der Weg für langfristig entkoppelte Architekturen.

Die häufigsten Fehler

Big Ball of Mud mit Ordnern: Verzeichnisstruktur allein ist keine Modularisierung. Ohne Build-Time-Checks erodiert jede Grenze innerhalb von Wochen.

Cross-Modul-Datenbankzugriffe: Modul A schreibt direkt in Tabellen von Modul B. Das zerstört die gesamte Prämisse. Ein Schreiber pro Datensatz. Immer.

Zu frühe Extraktion: Module als Microservices extrahieren, bevor die Grenzen stabil sind. Ergebnis: Ein verteilter Monolith. Das Schlimmste aus beiden Welten.

Chatty Cross-Module-Calls: Wenn eine User-Aktion fünf oder mehr Module synchron aufrufen muss, stimmen die Grenzen nicht.

Kein Team-Ownership: Jedes Modul braucht einen expliziten Verantwortlichen. Ohne Ownership erzwingt niemand die Grenzen.

Wann doch Microservices?

Sechs zuverlässige Signale, dass ein Modul reif für die Extraktion ist:

  1. Deployment-Bottleneck - Release-Koordination dauert länger als Feature-Entwicklung
  2. Divergierende Skalierung - Ein Modul braucht 10x die Ressourcen der anderen
  3. Unabhängige Delivery-Cycles - Teams blockieren sich gegenseitig bei Releases
  4. Incident Blast Radius - Fehler in einem Modul nehmen regelmäßig andere Module mit
  5. Compliance-Isolation - Regulatorische Anforderungen verlangen Service-Level-Trennung
  6. Technologie-Mismatch - Ein Modul braucht eine andere Runtime oder Sprache

Wenn keines dieser Signale zutrifft: Bleiben Sie beim Modulith. Das ist kein Kompromiss - das ist die richtige Architekturentscheidung.

Fazit

Microservices sind ein Werkzeug, keine Religion. Der Modulith ist kein Zwischenschritt auf dem Weg zu Microservices - er ist für die Mehrheit der Teams die Zielarchitektur.

Der pragmatische Weg: Domänen verstehen. Grenzen erzwingen. Module definieren. Und nur dort extrahieren, wo Daten, Skalierung oder Team-Autonomie es nachweislich verlangen.

Shopify betreibt 2,8 Millionen Zeilen Ruby als Modulith und verarbeitet 284 Millionen Requests pro Minute am Black Friday. Die Architektur skaliert. Die Frage ist nur, ob Ihr Problem wirklich ein Architekturproblem ist - oder ein Strukturproblem im bestehenden Code.

Der Selbsttest

Welche Architektur passt zu Ihrem Team? Fünf Fragen, eine Empfehlung.

Architektur-Check

Monolith, Modulith oder Microservices? Finden Sie es in 5 Fragen heraus.

Frage 1 / 5

Wie gross ist Ihr Entwicklungsteam?

Beitrag teilen

Passende Leistung

Digital Consulting

Jedes Projekt beginnt mit einem Gespräch.

Lassen Sie uns über Ihre individuellen Bedürfnisse und Wünsche sprechen.

Projekt anfragen