Warum verletzen umfangreiche Controller häufig das Single-Responsibility-Prinzip?
Umfangreiche Controller (oft als „Fat Controller“ bezeichnet) verletzen das Single-Responsibility-Prinzip (SRP), weil sie über ihre eigentliche Kernaufgabe hinauswachsen.
Nach dem SRP sollte eine Klasse nur einen Grund haben, sich zu ändern. Ein idealer Controller hat nur eine Aufgabe: Die Steuerung des Datenflusses.
Hier sind die spezifischen Gründe, warum große Controller gegen dieses Prinzip verstoßen:
1. Vermischung von Zuständigkeiten (Layer Mixing)
Ein Controller sollte lediglich die Anfrage (Request) entgegennehmen, die zuständige Geschäftslogik aufrufen und eine Antwort (Response) zurückgeben. Umfangreiche Controller übernehmen jedoch oft Aufgaben aus anderen Schichten:
- Geschäftslogik: Sie berechnen Rabatte, validieren komplexe Regeln oder verarbeiten Daten. (Gehört in den Service Layer oder das Domain Model).
- Datenbankzugriff: Sie führen direkt SQL-Queries oder ORM-Befehle aus. (Gehört in das Repository).
- Formatierung: Sie wandeln Daten mühsam in spezifische JSON-Strukturen oder HTML um. (Gehört in Presenter oder Resources).
Die Folge: Der Controller muss geändert werden, wenn sich die Datenbankstruktur ändert, wenn sich die Geschäftsregeln ändern UND wenn sich das API-Format ändert. Das sind drei Gründe statt einem.
2. Übernahme der Orchestrierung und Ausführung
Ein Controller sollte wie ein Verkehrspolizist (Orchestrator) fungieren: „Du gehst dorthin, du holst das.“ In großen Controllern wird er jedoch zum „Arbeiter“. Er weiß nicht nur, wer die E-Mail schicken soll, sondern er enthält auch den Code für den SMTP-Server, den E-Mail-Body und die Fehlerbehandlung beim Senden. Wenn er weiß, wie ein technischer Prozess im Detail funktioniert, hat er zu viel Verantwortung.
3. Handhabung von Querschnittsaufgaben (Cross-Cutting Concerns)
Häufig findet man in aufgeblähten Controllern Code für:
- Authentifizierung und Autorisierung.
- Logging und Monitoring.
- Caching-Logik.
Wenn diese Dinge direkt im Controller-Code stehen, ist er für die Sicherheit, die Performance-Überwachung und die Anwendungslogik gleichzeitig verantwortlich.
4. Schwierige Testbarkeit als Symptom
Das SRP zielt auch auf Testbarkeit ab. Ein Controller, der gegen das SRP verstößt, ist schwer isoliert zu testen. Um eine einzige Methode zu testen, müssen oft Datenbanken simuliert, Mail-Server gemockt und komplexe Abhängigkeiten aufgelöst werden. Dies zeigt, dass der Controller zu viele „Abhängigkeiten der Verantwortung“ hat.
5. Fehlende Wiederverwendbarkeit
Wenn Logik fest im Controller verbaut ist, kann sie nicht an anderer Stelle (z. B. in einem CLI-Befehl oder einem zeitgesteuerten Job) wiederverwendet werden. Die Logik ist an den HTTP-Request „gefangen“. Dies zwingt Entwickler oft dazu, Code zu kopieren, was wiederum gegen das DRY-Prinzip (Don't Repeat Yourself) verstößt und die Wartungsverantwortung vervielfacht.
Die Lösung: "Skinny Controller"
Um das SRP einzuhalten, nutzt man das Konzept der Skinny Controller (schlanke Controller):
- Request Validation: Form-Request-Klassen nutzen.
- Business Logic: In Services oder Domain Models auslagern.
- Data Access: Über Repositories abwickeln.
- Response Transformation: API-Ressourcen oder Transformer nutzen.
Fazit: Ein Controller verletzt das SRP immer dann, wenn er mehr tut als nur Eingaben entgegenzunehmen, den richtigen Dienst aufzurufen und das Ergebnis zurückzugeben.