Was Architektur ist (und nicht ist)
"Architektur ist die Menge der Entscheidungen, die später teuer zu ändern sind." - Ralph Johnson
Architektur ist nicht "welches Framework haben wir verwendet" - das ist ein Implementierungsdetail. Architektur ist die Form, die Sie beim Navigieren durch die Codebasis spüren: wie Module aufgeteilt sind, in welche Richtung Abhängigkeiten fließen, welcher Code welchen aufrufen darf.
Gute Architektur sagt einem Entwickler ohne Mehrdeutigkeit, wo das neue Feature zu schreiben ist. Schlechte Architektur macht diese Frage jedes Mal zu einer Debatte.
Die Kosten von Entscheidungen
Die wahren Kosten einer Architekturentscheidung zeigen sich nicht im Moment der Entscheidung, sondern wenn die Zahl der nachgelagerten Entscheidungen wächst. Drei Maße:
- Umkehrzeit - wie viele Wochen zum Rückgängigmachen?
- Verbreitungsfläche - wie viele Dateien / Module hängen von dieser Entscheidung ab?
- Kognitive Last - wie viele Stunden braucht ein neuer Entwickler, um es zu verstehen?
Bevor Sie eine Entscheidung festschreiben, fragen Sie: Wenn ich in drei Monaten merke, dass dies falsch ist, wie schmerzhaft ist die Umkehrung?
Absicht vs. Umsetzung
Architektur ist die Summe der Entscheidungen, die Sie treffen wollten; die Codebasis ist das, was tatsächlich gebaut wurde. Die Lücke dazwischen ist Architektur-Drift - und sie wächst still, bis eine Änderung, die eine Stunde dauern sollte, eine Woche braucht.
Die Aufgabe ist nicht, einmal das perfekte Diagramm zu zeichnen. Es geht darum, Absicht und Umsetzung so nah beieinander zu halten, dass das Diagramm immer noch vorhersagt, wie sich der Code verhält.
Schichten (n-tier)
Die klassische Aufteilung: Präsentation → Anwendung → Domäne → Daten. Jede Schicht darf nur die darunterliegende aufrufen. Das am leichtesten zu lehrende Modell - und das am leichtesten zu verletzende: ein Aufruf von der UI direkt in die Datenschicht, und die Schichtung ist eine Fiktion.
Verwenden Sie es, wenn das Team klein und die Domäne flach ist. Seine Schwäche: Geschäftslogik neigt dazu, nach oben in die Controller und nach unten in die Datenbank zu sickern.
Hexagonal · Ports & Adapter
Die Domäne sitzt im Zentrum und weiß nichts über die Außenwelt. Alles Externe - Datenbank, HTTP, Message Queue - spricht über Ports (Schnittstellen) mit ihr, die von Adaptern implementiert werden.
Der Gewinn ist Testbarkeit und Austauschbarkeit: Sie können Postgres in Tests durch ein In-Memory-Fake ersetzen oder REST durch gRPC, ohne eine Zeile Domänencode anzufassen.
Clean Architecture
Eine Verfeinerung des Hexagonalen: konzentrische Ringe, in denen Abhängigkeiten ausschließlich nach innen zeigen, zu den Domänen-Entitäten. Frameworks, UI und Datenbanken liegen im äußersten Ring - Details, nicht der Kern.
Es verschafft Ihnen eine Domäne, die ohne jede Infrastruktur kompiliert und getestet wird. Der Preis ist Zeremonie - mehr Schnittstellen, mehr Mapping. Lohnend für langlebige Systeme, übertrieben für ein CRUD-Admin-Panel.
DDD - Domain-Driven Design
DDD ist kein Framework - es ist eine Vokabular-Disziplin. "Aggregate", "bounded context", "anti-corruption layer" - eine gemeinsame Sprache, um über das Problem zu sprechen.
Wann DDD?
- Die Domäne ist komplex und wird oft mit technischer Komplexität verwechselt.
- Mehrere Teams arbeiten an derselben Domäne.
- Business und Entwicklung sprechen unterschiedliche Sprachen.
DDD ist nicht für jedes Projekt. Wenn es sich für ein CRUD-lastiges Admin-Panel zu schwer anfühlt, ist es das wahrscheinlich auch.
Big Ball of Mud
Keine erkennbare Architektur: alles hängt von allem ab, der Zustand wird global geteilt, und der einzige Weg, eine Änderung zu verstehen, ist sie auszuführen. Die meisten Systeme landen hier nicht durch eine Entscheidung, sondern durch tausend Deadlines.
Man schreibt einen Big Ball of Mud nicht neu - man würgt ihn ab. Eine Naht umhüllen, eine Fähigkeit hinter eine saubere Schnittstelle ziehen, wiederholen. Die Abhängigkeitskarte von AppArch zeigt Ihnen, wo die Nähte schon sind.
Antipattern: Gott-Modul
Ein "Gott-Modul" ist dasjenige, das von überall aufgerufen wird und alles enthält. Namen wie Utils, Common, Shared sind Warnzeichen.
# eine Regel, die es erkennt - id: GOD-001 max_fan_in: 25 message: "Module imported by >25 files - split or rename"
Lösung: in grob drei Teile aufteilen. Gruppe eins ist echte Infrastruktur (Logger, Config). Gruppe zwei sind Domänen-Primitive (Money, Id). Gruppe drei ist wahrscheinlich ein eigenes Modul, das sich darin versteckt.
Zirkuläre Abhängigkeiten
Modul A braucht B, B braucht A. Nun lässt sich keines allein verstehen, testen oder ausliefern, und die Build-Reihenfolge wird zum Münzwurf. Zyklen sind der zuverlässigste Vorbote eines Moduls, das niemand anfassen will.
Brechen Sie den Zyklus, indem Sie das gemeinsame Konzept in ein drittes Modul auslagern, von dem beide abhängen, oder eine Richtung mit einer Schnittstelle umkehren. AppArch markiert Zyklen, sobald sie in einem Merge Request auftauchen.
Undichte Abstraktionen
Eine Abstraktion ist undicht, wenn man wissen muss, wie sie implementiert ist, um sie korrekt zu nutzen - ein Repository, das SQL-Ausnahmen wirft, ein Cache, der Aufrufer zwingt, Veraltung zu behandeln. Sie versprach, ein Detail zu verbergen, und tat es nicht.
Entweder dichten Sie das Leck ab - übersetzen Sie Implementierungsfehler an der Grenze - oder lassen Sie die Abstraktion fallen. Eine undichte ist schlimmer als keine: Sie zahlen für die Indirektion, ohne die Isolation zu bekommen.
Architektur-Review
Ein Review ist kein Tor, das Merges blockiert; es ist ein Gespräch darüber, ob eine Änderung das System auf seine beabsichtigte Form zu- oder von ihr wegbewegt. Die besten Reviews fragen eher 'was macht das später schwer?' als 'ist das jetzt korrekt?'
Halten Sie es leichtgewichtig und kontinuierlich. Ein kurzes Review bei jedem bedeutsamen Merge Request schlägt ein vierteljährliches Architektur-Gremium, das alle umgehen.
Architecture Decision Records
Ein ADR hält eine Entscheidung fest: den Kontext, die erwogenen Optionen, die Wahl und ihre Konsequenzen - ein, zwei Absätze, versioniert neben dem Code. Sechs Monate später beantwortet es die einzige Frage, die zählt: Warum ist das so?
Schreiben Sie das ADR, wenn die Entscheidung fällt, nicht danach. Ersetzen statt löschen - die Spur, warum Sie Ihre Meinung geändert haben, ist so wertvoll wie die aktuelle Antwort.
Große Refactorings
Ein großes Refactoring, das als ein einziger riesiger Merge landet, ist ein getarntes Rewrite - und es wird beim ersten Fehler zurückgerollt. Echtes Refactoring ist eine Folge kleiner, verhaltenserhaltender Schritte, jeder für sich auslieferbar.
Fügen Sie den neuen Pfad neben dem alten hinzu, migrieren Sie Aufrufer schrittweise, löschen Sie dann den alten Pfad. Tests sind das Sicherungsseil; ohne sie refactoren Sie nicht, Sie zocken.