Schichtenarchitektur und Clean Architecture: Abhängigkeiten richtig ordnen
Kurz: Eine gute Architektur trennt Oberfläche, Fachlogik und Datenzugriff und lässt Abhängigkeiten nur nach innen zeigen, damit Geschäftsregeln unabhängig von Frameworks und Datenbanken bleiben.
Genauer: Wächst eine Anwendung, vermischen sich oft HTML, Datenbankabfragen und Geschäftsregeln in denselben Dateien. Änderungen werden riskant. Architekturmuster schaffen Ordnung.
Im Detail
Klassische Schichten
- Präsentation (UI, Controller, API-Endpunkte).
- Anwendungs-/Fachlogik (Services, Regeln, Abläufe).
- Datenzugriff (Repositories, ORM, Datenbank). Anfragen gehen von oben nach unten. Vorteil: einfach, verbreitet. Nachteil: Die Fachlogik hängt oft von der Datenbank ab, und Schichten „lecken“ (SQL im Controller).
Clean/Hexagonale/Onion-Architektur
Diese Ansätze (Robert C. Martin, Alistair Cockburn) stellen die Fachlogik in die Mitte und lassen Abhängigkeiten nur nach innen zeigen:
[UI / Web] [Datenbank] [Externe APIs] <- Details außen
\ | /
[Adapter / Schnittstellen]
|
[Anwendungsfälle (Use Cases)]
|
[Entitäten / Fachregeln] <- Kern
Der Kern definiert Schnittstellen (Ports), zum Beispiel BestellungRepository; die Datenbank-Implementierung (Adapter) liegt außen und wird per Dependency Injection eingesteckt. Dadurch lassen sich Datenbank, Framework oder UI austauschen, und die Fachlogik ist ohne Infrastruktur testbar.
Typische Bausteine
- Entität/Domänenmodell: Fachobjekte mit Regeln (
Bestellung). - Use Case/Service: ein Anwendungsfall („Bestellung aufgeben“).
- Repository: abstrahiert Speicherung (
speichern,findeNachId). - DTO (Data Transfer Object): einfache Datenstruktur für Ein-/Ausgaben an den Grenzen.
- Controller/Handler: übersetzt HTTP in Use-Case-Aufrufe.
- Mapper: wandelt zwischen Schichten (Entität ↔ DTO).
Wann lohnt sich das?
Bei langlebigen, komplexen Anwendungen mit vielen Regeln und mehreren Teams. Bei kleinen Projekten oder Prototypen ist zu viel Struktur Overengineering: Beginne einfach (zum Beispiel ein sauber gegliederter modularer Monolith), trenne Fachlogik von Framework-Code und führe Abstraktionen erst ein, wenn sie gebraucht werden. Wichtiger als das Muster sind klare Verantwortlichkeiten und Abhängigkeitsrichtung.
Siehe auch: Hexagonale Architektur, Modularer Monolith, Dependency Injection, SOLID-Prinzipien