Welche Probleme entstehen bei der Wartung, wenn Controller zu viele verschiedene Services koordinieren?
Wenn ein Controller zu viele verschiedene Services koordiniert, spricht man oft von einem „Fat Controller“ oder einem „God Object“. In der Softwarearchitektur (besonders bei MVC oder Microservices) führt dies zu erheblichen Wartungsproblemen.
Hier sind die spezifischen Probleme, die dadurch entstehen:
1. Verletzung des Single Responsibility Principle (SRP)
Das SRP besagt, dass eine Klasse nur einen Grund für Änderungen haben sollte. Ein Controller, der zehn Services orchestriert, hat plötzlich zehn oder mehr Gründe, sich zu ändern (wenn sich Service A ändert, wenn die Geschäftslogik für Prozess B variiert, wenn die Datenstruktur von Service C angepasst wird etc.). Der Controller mutiert von einer einfachen „Eingangstür“ zur eigentlichen Logikzentrale.
2. Erschwerte Testbarkeit (Unit Testing)
Dies ist eines der größten praktischen Probleme:
- Aufwendiges Mocking: Um einen einzigen Endpoint im Controller zu testen, müssen im Test-Setup alle zehn Services „gemockt“ (simuliert) werden.
- Fragile Tests: Die Tests werden extrem umfangreich und schwer lesbar. Wenn sich eine Kleinigkeit in einem Service ändert, brechen plötzlich Dutzende Controller-Tests ab, obwohl die Logik des Controllers selbst vielleicht gar nicht betroffen ist.
3. Starke Kopplung (Tight Coupling)
Der Controller wird zum „Knotenpunkt“, an dem alles zusammenläuft. Das macht das System unflexibel:
- Abhängigkeits-Hölle: Änderungen in einem untergeordneten Service können unvorhersehbare Auswirkungen auf den Controller und damit auf andere Services haben.
- Erschwerter Austausch: Es ist fast unmöglich, einen Service auszutauschen oder zu aktualisieren, ohne den massiven Controller-Code anzupassen.
4. Hohe kognitive Komplexität
Für Entwickler (besonders neue Teammitglieder) ist es extrem schwierig, den Überblick zu behalten:
- Lesbarkeit: Methoden im Controller werden sehr lang, da sie die Orchestrierung (zuerst Service A, dann Ergebnis in Service B, wenn Fehler, dann Service C) manuell handhaben.
- Fehleranfälligkeit: Es ist schwer vorherzusehen, welche Seiteneffekte ein Aufruf hat, wenn im Hintergrund eine Kaskade von Services angestoßen wird.
5. Probleme beim Transaktionsmanagement und Konsistenz
Wenn ein Controller fünf Services nacheinander aufruft, die jeweils eigene Datenbankoperationen durchführen:
- Atomarität: Was passiert, wenn Service 1 und 2 erfolgreich sind, aber Service 3 fehlschlägt?
- Rollback-Chaos: Da der Controller meist nicht auf der Datenbankebene (Transaktionsebene) arbeitet, ist es sehr schwer, einen konsistenten Zustand wiederherzustellen (Saga-Pattern oder manuelle Rollbacks wären nötig, was den Controller noch komplexer macht).
6. Mangelnde Wiederverwendbarkeit
Die Logik, wie diese Services zusammenarbeiten, ist nun im Controller „gefangen“.
- Wenn ein anderer Teil des Systems (z. B. ein CLI-Tool, ein Background-Job oder ein zweiter Controller) die gleiche Abfolge von Services benötigt, muss die Logik kopiert werden (Duplizierung) oder der Controller muss mühsam extrahiert werden.
7. Performance-Engpässe
Controller-Methoden, die viele Services koordinieren, neigen dazu, sequentiell zu arbeiten. Oft werden Daten von Service A geholt, um sie an Service B zu senden. Dies führt zu langen Antwortzeiten (Latency), besonders wenn es sich um Remote-Services (Microservices) handelt.
Die Lösung: Wie macht man es besser?
Um diese Probleme zu vermeiden, sollte man Orchestrierungs-Schichten einführen:
- Service Layer / Domain Services: Man erstellt einen "Über-Service" (z. B.
OrderProcessingService), der die Koordination der kleinen Services übernimmt. Der Controller ruft nur noch diesen einen Service auf. - Facade Pattern: Eine Fassade bietet eine einfache Schnittstelle zu einem komplexen Subsystem aus vielen Services.
- Command Pattern / MediatR: Besonders in .NET-Umgebungen beliebt. Der Controller sendet nur ein "Command", und ein spezifischer Handler kümmert sich um die gesamte Orchestrierung.
- Orchestrator Pattern (bei Microservices): Ein dedizierter Service übernimmt die Workflow-Steuerung.
Fazit: Ein Controller sollte idealerweise nur Anfragen entgegennehmen, validieren und an einen (oder sehr wenige) Business-Service weitergeben. Die eigentliche „Intelligenz“ der Koordination gehört in die Business-Logik-Schicht.