Read in English · Leer en español · Lire en français
Abschnitt 5.2 von 5.8 · Mittelstufe · 24 Min. Lesezeit
Schichtenarchitektur
Videolektion
5 Min. · auf Englisch gesprochen, mit UntertitelnNur anhören (Audio)
Transkript lesen
Die Schichtenarchitektur ist der am weitesten verbreitete Stil für Geschäftsanwendungen, oft eher aus Gewohnheit als aus einer Entscheidung heraus gewählt. In dieser Lektion lernen Sie, wie sie funktioniert, was sie kostet und wie Sie verhindern, dass ihre Regeln erodieren.
Denken Sie an ein Restaurant. Die Gäste sprechen nur mit dem Servicepersonal. Das Servicepersonal gibt Bestellungen an die Küche weiter und geht nie selbst ins Lager. Die Köche holen Zutaten beim Lagerpersonal, und nur das Lagerpersonal hat mit Lieferanten zu tun. Jede Gruppe hat eine Aufgabe und spricht nur mit der Gruppe neben ihr, sodass Sie das Servicepersonal umschulen können, ohne die Küche anzurühren. Eine Anwendung in Schichtenarchitektur funktioniert genauso.
Hier ist eine Essensbestell-Anwendung in Schichten. Eine Anfrage aus Browser oder App kommt in der Präsentationsschicht an, die Bildschirmmasken, HTTP und JSON verarbeitet. Die Geschäftsschicht enthält die Regeln und Anwendungsfälle: wie eine Bestellung bepreist wird und wann sie storniert werden darf. Die Persistenzschicht wandelt Geschäftsobjekte in gespeicherte Daten und zurück. Nur sie spricht mit der Datenbank. Diese Schichten sind geschlossen: Eine Anfrage muss sie durchlaufen. Die Präsentation darf nicht an der Geschäftsschicht vorbei in die Persistenz greifen, auch wenn das schneller zu schreiben wäre. Und keine Schicht darf jemals nach oben aufrufen. Die Dienstschicht für E-Mails, PDF-Belege und Audit-Einträge ist offen. Nur manche Operationen brauchen sie, daher darf die Geschäftsschicht sie aufrufen oder direkt an ihr vorbei zur Persistenz gehen.
Geschlossene Schichten ergeben Isolationsschichten. Weil die Präsentation nur die Schnittstelle der Geschäftsschicht kennt, kann das Team die Tabellen umstrukturieren oder sogar das Datenbankprodukt wechseln, ohne eine einzige Bildschirmmaske anzurühren. Jede Ausnahme, die einer Schicht erlaubt, eine andere zu überspringen, schwächt das. Fragen Controller die Datenbank direkt ab, greift eine Schemaänderung nun auch auf die Präsentationsschicht über.
Verfolgen wir eine Anfrage. Ein Kunde drückt auf Bestellen. Die Präsentationsschicht parst die Anfrage, prüft, ob der Benutzer angemeldet ist, und ruft den Bestellservice auf. Sie weiß nichts über Tabellen oder Preise. Die Geschäftsschicht prüft, ob das Restaurant geöffnet hat, bepreist den Warenkorb und bittet das Repository, die Bestellung zu speichern. Außerdem nutzt sie die offene Dienstschicht, um einen Beleg per E-Mail zu senden. Die Persistenzschicht bildet die Bestellung auf Zeilen ab und schreibt sie in einer Datenbanktransaktion. PostgreSQL committet, und das Ergebnis fließt nach oben zurück. Der Kunde sieht seine Bestellnummer. Nun wünscht sich das Produktteam ein Kurier-Trinkgeld. Das braucht ein Feld in der Anfrage, eine Regel für das maximale Trinkgeld, eine neue Spalte und eine Migration. Vier Schichten für ein kleines Feature: die Kosten technischer Partitionierung.
Die Schichtenbildung hat ein klassisches Anti-Pattern, das Architecture Sinkhole: Anfragen, die durch Schichten laufen, die sie nur weiterreichen. Eine Speisekarte anzusehen ist typisch. Der Controller reicht weiter, der Service reicht weiter, und nur das Repository leistet Arbeit. Vergleichen Sie das mit einer Bestellung, bei der jede Schicht Verhalten hinzufügt: prüfen, bepreisen, Regeln kontrollieren und dann in einer Transaktion speichern. Ein gewisses Maß an Durchreichen ist der Preis der Isolation. Als Faustregel ist etwa ein Fünftel der Anfragen normal. Reichen die meisten Anfragen nur durch, ist die Schichtenbildung wahrscheinlich der falsche Stil.
Der Stil schneidet bei Einfachheit und niedrigen Kosten gut ab: fast jedem Entwicklungsteam vertraut, mit einer Codebasis, einem Deployment und einer Datenbank. Bei Deploybarkeit, Skalierbarkeit und Fehlertoleranz schneidet er schlecht ab. Jede Änderung deployt alles neu, die ganze Anwendung skaliert als Einheit, und ein Speicherleck kann alles lahmlegen. Sie passt gut zu kleinen und mittleren Anwendungen, die ein Team baut, und zu Anwendungen, die überwiegend aus Formularen über Daten bestehen. Als oberste Ebene eines großen Systems mit mehreren Teams passt sie schlecht, weil jedes Team in jeder Schicht arbeitet. Der übliche nächste Schritt ist ein modularer Monolith mit Schichten innerhalb jedes Moduls.
Schichtenregeln verfallen schnell. Jemand importiert das Repository direkt in einen Controller, um zwanzig Minuten zu sparen, niemand bemerkt es, und der Nächste kopiert es. Die Abwehr ist ein Architekturtest: eine automatisierte Prüfung von Abhängigkeiten, die im Build läuft und ihn scheitern lässt, wenn eine Regel verletzt wird. In Python liest import-linter die Regeln aus einer Konfigurationsdatei. In Java drückt ArchUnit sie als Unit-Test aus. Erfassen Sie zu Beginn die vorhandenen Verstöße als bekannte Ausnahmen, sodass nur neue den Build scheitern lassen. Bauen Sie die Ausnahmen dann nach und nach ab.
Der vollständige Abschnitt enthält die Merkmalstabelle, weitere Anti-Patterns und eine funktionierende import-linter-Konfiguration. Als Nächstes behalten wir in Abschnitt fünf Punkt drei ein Deployment bei, teilen es aber nach Fachdomänen auf: der modulare Monolith. Bis gleich.
Was Sie wissen müssen
- Eine Schichtenarchitektur ordnet Code in horizontalen Schichten nach technischer Rolle an, typischerweise Präsentation, Geschäftslogik, Persistenz und Datenbank, und lässt jede Schicht nur von Schichten unter ihr abhängen.
- Geschlossene Schichten dürfen nicht übersprungen werden, was Isolationsschichten ergibt: Eine Änderung innerhalb einer Schicht greift nicht auf andere über, solange ihre Schnittstelle hält. Eine offene Schicht, etwa eine Schicht gemeinsamer Dienste, darf umgangen werden.
- Schichtenbildung ist technische Partitionierung, daher betrifft ein typisches fachliches Feature jede Schicht; das verlangsamt Änderungen und legt Teamstrukturen nach Schichten nahe.
- Das Anti-Pattern Architecture Sinkhole bezeichnet Anfragen, die durch Schichten laufen, die sie nur weiterreichen; als Faustregel ist eine Minderheit solcher Anfragen normal, eine große Mehrheit deutet auf den falschen Stil hin.
- Der Stil schneidet bei Einfachheit und niedrigen Kosten gut ab und bei Deploybarkeit, Skalierbarkeit, Elastizität und Fehlertoleranz schlecht, weil das ganze System eine Deployment-Einheit ist.
- Schichtenregeln erodieren, wenn sie nicht automatisch durchgesetzt werden, zum Beispiel mit import-linter in Python oder ArchUnit in Java, als Tests, die den Build scheitern lassen.
Definition und Ursprung
Eine Schichtenarchitektur gliedert eine Anwendung in horizontale Schichten, von denen jede eine technische Verantwortung hat, der Schicht darüber Dienste anbietet und die Dienste der Schicht darunter nutzt. Sie ist der am weitesten verbreitete Stil für Geschäftsanwendungen, oft eher aus Gewohnheit als aus einer Entscheidung heraus, weil die meisten Web-Frameworks ein Projekt mit Ordnern für Views, Geschäftslogik und Models erzeugen.
Die Idee ist alt und stammt aus der Systemsoftware. Edsger Dijkstra beschrieb das Multiprogramming-Betriebssystem THE (Communications of the ACM, 1968) als Hierarchie von Ebenen, von denen jede nur auf den darunterliegenden aufbaut, sodass sich jede Ebene für sich betrachten und testen ließ. Netzwerkprotokollstapel wie das OSI-Referenzmodell nutzen dasselbe Prinzip. In der Geschäftssoftware kam die Schichtenbildung mit Client-Server- und dreistufigen Systemen in den 1990er-Jahren an, und POSA (1996) katalogisierte sie als Layers-Muster. Garlan und Shaw führten Schichtensysteme unter ihren grundlegenden Stilen auf, mit der Randbedingung, dass Interaktionen auf benachbarte Schichten beschränkt sind.
Die typische Geschäftsanwendung hat vier Schichten. Die Präsentationsschicht kümmert sich um die Benutzeroberfläche und das Protokoll: HTTP-Anfragen, Bildschirmmasken, JSON. Die Geschäftsschicht enthält die Regeln und Anwendungsfälle: wie eine Bestellung bepreist wird, wann sie storniert werden darf. Die Persistenzschicht wandelt Geschäftsobjekte in gespeicherte Daten und zurück, meist über Repositories und einen objektrelationalen Mapper. Die Datenbankschicht ist die Datenbank selbst. Kleine Anwendungen legen Geschäftslogik und Persistenz manchmal zusammen; größere fügen Schichten hinzu, etwa eine Anwendungsschicht, die Anwendungsfälle über einer Domänenschicht mit dem Kernmodell koordiniert. Der Stil legt nicht die Anzahl fest, sondern die Richtung der Abhängigkeit.
Eine Essensbestell-Anwendung in Schichten
Funktionsweise: geschlossene Schichten, offene Schichten und Isolation
Jede Schicht kann geschlossen oder offen sein. Eine Anfrage muss eine geschlossene Schicht durchlaufen: Die Präsentationsschicht darf nicht an der Geschäftsschicht vorbei in die Persistenzschicht greifen, auch wenn das schneller zu schreiben wäre. Eine offene Schicht darf umgangen werden. Das übliche Beispiel ist eine Schicht gemeinsamer technischer Dienste, etwa für den E-Mail-Versand, das Erzeugen von PDF-Belegen oder das Schreiben von Audit-Einträgen. Nur manche Geschäftsoperationen brauchen sie, daher würde es sinnlosen Weiterleitungscode erzeugen, jede Anfrage durch diese Schicht zu zwingen. Im Diagramm darf die Geschäftsschicht die Dienstschicht aufrufen oder direkt an ihr vorbei zur Persistenz gehen.
Geschlossene Schichten ergeben Isolationsschichten (Layers of Isolation). Weil die Präsentationsschicht nur die Schnittstelle der Geschäftsschicht kennt, kann das Team den objektrelationalen Mapper ersetzen, die Tabellen umstrukturieren oder von einem Datenbankprodukt zu einem anderen wechseln, ohne einen einzigen Controller oder ein Template anzurühren, solange die Schnittstelle der Geschäftsschicht gleich bleibt. Das ist Information Hiding (David Parnas, 1972), angewandt auf eine ganze Ebene des Codes, und es ist der Hauptnutzen, den der Stil bietet. Jede offene Schicht und jede Ausnahme, die einer Schicht erlaubt, eine andere zu überspringen, schwächt ihn: Fragen Controller die Datenbank direkt ab, greift eine Schemaänderung nun auch auf die Präsentationsschicht über.
Die Richtung der Abhängigkeit ist die andere Hälfte der Regel. Untere Schichten dürfen nichts von höheren wissen: Die Persistenzschicht darf nie einen Controller importieren, und die Geschäftsschicht darf nie HTML erzeugen. Muss eine untere Schicht eine höhere benachrichtigen, geschieht das über eine Abstraktion, die der unteren Schicht gehört, etwa eine Callback-Schnittstelle oder ein Event, sodass die Abhängigkeit im Code weiterhin nach unten zeigt. Abschnitt 3.4 behandelt Abhängigkeitsrichtung, Zyklen und strikte gegenüber gelockerter Schichtenbildung ausführlich.
Es hilft, Schichten und Tiers auseinanderzuhalten. Eine Schicht ist eine logische Gruppierung im Code. Ein Tier ist eine physische Grenze zur Laufzeit, etwa ein separater Server oder Prozess. Ein klassisches Three-Tier-System betreibt Browser, Anwendungsserver und Datenbankserver als drei Tiers, während der Anwendungsserver allein drei oder vier Schichten enthalten kann. Macht man aus einer Schicht ein Tier, liegt ein Netzwerk zwischen zwei Schichten, die einander vorher im Arbeitsspeicher aufgerufen haben, was die Kosten jedes Aufrufs vervielfacht; das lohnt sich selten um seiner selbst willen.
Beispiel: eine klassische Webanwendung
Nehmen wir die Bestellwebsite eines regionalen Essenslieferunternehmens: Kunden sehen sich Speisekarten an, geben Bestellungen auf und bezahlen; das Restaurantpersonal sieht eingehende Bestellungen. Ein Team aus fünf Personen baut sie mit einem verbreiteten Web-Framework und einer PostgreSQL-Datenbank. Eine Schichtenstruktur ist der naheliegende Ausgangspunkt, und die Codeaufteilung macht die Schichten sichtbar.
foodshop/
presentation/ # HTTP only: parse requests, render responses
order_views.py
menu_views.py
templates/
business/ # rules and use cases; no HTTP, no SQL
order_service.py
pricing.py
services/ # open layer: shared technical services
email.py
receipts.py
persistence/ # all database access
order_repository.py
menu_repository.py
models.py
settings.pyAusgearbeitetes Beispiel
Ausgearbeitetes Beispiel: eine Anfrage durch die Schichten verfolgen
Ein Kunde drückt auf Bestellen. Die Anfrage kommt als POST /orders mit dem Warenkorb und der Lieferadresse an.
| Präsentation | order_views.place_order parst das JSON, prüft, ob es wohlgeformt ist und ob der Benutzer angemeldet ist, und ruft order_service.place(customer_id, items, address) auf. Es weiß nichts über Tabellen oder Preise. |
|---|---|
| Geschäftslogik | order_service.place prüft, ob das Restaurant geöffnet hat, bepreist den Warenkorb mit pricing.py (Rabatte, Liefergebühr, Steuer) und bittet order_repository, die Bestellung zu speichern. Es ruft receipts.send in der offenen Dienstschicht auf, um einen Beleg per E-Mail zu senden. |
| Persistenz | order_repository.save bildet die Bestellung auf Zeilen in orders und order_lines ab und schreibt sie in einer Datenbanktransaktion. |
| Datenbank | PostgreSQL committet die Transaktion und kehrt zurück. Das Ergebnis fließt nach oben zurück: Der Service gibt die neue Bestellung zurück, die View rendert 201 Created mit der Bestellnummer. |
| Änderungswunsch | Das Produktmanagement wünscht sich ein Kurier-Trinkgeld. Die Entwicklerin fügt ein Trinkgeldfeld in Anfrage und Antwort hinzu (Präsentation), eine Regel für das maximale Trinkgeld und das Trinkgeld in der Gesamtsumme (Geschäftslogik) sowie eine Spalte und ein Mapping (Persistenz), dazu eine Migration (Datenbank). Vier Schichten für ein kleines Feature. |
Jede Schicht erledigte eine Art von Aufgabe, und jede ließ sich allein testen, wobei die Schicht darunter durch ein Test Double ersetzt wurde.
Das Trinkgeld zeigt die Kosten technischer Partitionierung: Selbst eine kleine fachliche Änderung zieht sich durch jede Schicht, betrifft also mehr Dateien, mehr Reviewer und, wenn die Teams nach Schichten aufgeteilt sind, mehr Teams.
Die Folgen technischer Partitionierung
Weil Schichtenbildung technische Partitionierung ist, wird die Fachdomäne über die Schichten verschmiert. Es gibt keinen einzelnen Ort namens Lieferung
: Es gibt Liefer-Controller, Liefer-Services und Liefer-Repositories, vermischt mit allem anderen in jeder Schicht. Wer verstehen will, wie Trinkgeld funktioniert, muss quer durch alle lesen. Mit dem Wachstum des Systems wird jede Schicht zu einer großen Sammlung unzusammenhängenden Codes mit geringer Kohäsion: Die Geschäftsschicht enthält Regeln für Bestellungen, Zahlungen, Speisekarten und Kuriere nebeneinander, und nichts hindert den Zahlungscode daran, tief in den Speisekartencode hineinzurufen. Mit der Zeit bleiben die Schichten sauber, aber das Innere jeder Schicht wird zu einem Big Ball of Mud.
Es gibt auch organisatorische Kosten. Teams nach Schichten zu organisieren (ein Frontend-Team, ein Backend-Team, ein Datenbankteam) bedeutet, dass fast jedes Feature eine Übergabe und eine Warteschlange zwischen Teams braucht, was das Gesetz von Conway dann in der Architektur festschreibt. Martin Fowler bezeichnet nach Schichten organisierte Teams aus diesem Grund als Anti-Pattern: Die einzelnen Entwickler müssen nicht Full-Stack sein, die Teams aber schon. Eine Schichtenarchitektur zwingt Teams nicht, sich nach Schichten aufzuteilen, macht es aber zum Weg des geringsten Widerstands.
Schließlich ist ein Schichtenmonolith ein einziges Architekturquantum: eine Deployment-Einheit und meist eine Datenbank. Jede Änderung, so klein sie auch ist, bedeutet, die ganze Anwendung zu bauen, zu testen und neu zu deployen, und die ganze Anwendung skaliert und fällt als Einheit aus. Das ist oft völlig akzeptabel, setzt aber eine Obergrenze.
Das Architecture Sinkhole und andere Anti-Patterns
Das Anti-Pattern Architecture Sinkhole, ein von Mark Richards bekannt gemachter Name, beschreibt Anfragen, die durch Schichten fließen, die nichts tun, als sie weiterzureichen. Eine Speisekarte anzusehen ist der typische Fall: Der Controller ruft eine Servicemethode auf, die eine Repository-Methode aufruft, die eine Abfrage ausführt, und Controller und Service fügen nichts hinzu. Jede durchreichende Schicht bringt Code mit sich, der geschrieben, getestet und gelesen werden muss, und ein wenig Latenz. Ein gewisses Maß an Durchreichen ist der Preis der Isolation und in Ordnung. Richards bietet eine Faustregel an: Ist etwa ein Fünftel der Anfragen einfaches Durchreichen, ist das normal; sind es die meisten, besteht die Anwendung wahrscheinlich überwiegend aus Datenzugriff mit wenig Geschäftslogik, und die Schichtenbildung ist der falsche Stil oder die Schichten sollten geöffnet werden. Schichten zu öffnen gibt allerdings Isolation auf, also entscheiden Sie bewusst und halten Sie fest, warum.
Weitere häufige Anti-Patterns sollte man früh erkennen. Undichte Schichten: SQL in Controllern, HTTP-Anfrageobjekte, die an Services übergeben werden, oder ORM-Entitäten, die direkt als JSON gerendert werden, sodass eine Änderung in einer Schicht auf andere übergreift. Abhängigkeiten nach oben: ein Repository, das einen Service aufruft, oder ein Domänenobjekt, das HTML formatiert. Die anämische Geschäftsschicht: Services, die nur Daten umherschieben, während die eigentlichen Regeln in Controllern oder Stored Procedures leben; Fowler benannte 2003 das verwandte Anti-Pattern Anemic Domain Model. Der Gott-Service: ein OrderService mit mehreren tausend Zeilen, den jeder andere Service aufruft. Die Utility-Schicht, von der alles abhängt: ein common-Paket, das nach und nach Geschäftslogik ansammelt und alles mit allem koppelt.
Sinkhole oder nützliche Schichtenbildung
Merkmale des Schichtenstils
| Merkmal | Bewertung | Begründung |
|---|---|---|
| Einfachheit | Hoch | Fast jedem Entwicklungsteam vertraut und die Standardstruktur der meisten Frameworks; leicht zu erklären und zu beginnen. |
| Gesamtkosten | Hoch (günstig) | Eine Codebasis, ein Deployment, eine Datenbank; minimale Infrastruktur und minimaler Betrieb. |
| Testbarkeit | Mittel | Jede Schicht lässt sich testen, indem die Schicht darunter durch ein Test Double ersetzt wird, aber realistische Tests brauchen oft den ganzen Stack und eine Datenbank. |
| Änderbarkeit bei fachlichen Änderungen | Niedrig bis mittel | Technische Änderungen bleiben innerhalb einer Schicht, aber die meisten Feature-Änderungen ziehen sich durch jede Schicht. |
| Deploybarkeit | Niedrig | Jede Änderung bedeutet, die ganze Anwendung neu zu deployen; das Release-Risiko wächst mit der Größe. |
| Skalierbarkeit und Elastizität | Niedrig | Die ganze Anwendung skaliert als eine Einheit; man kann nicht nur den ausgelasteten Teil skalieren, und der Start einer großen Anwendung bremst elastisches Skalieren. |
| Fehlertoleranz | Niedrig | Ein Speicherleck oder eine außer Kontrolle geratene Abfrage kann den ganzen Prozess lahmlegen; es gibt keine Isolation zwischen Features. |
| Performance | Mittel | Aufrufe im selben Prozess sind schnell, aber zusätzliche Schichten und Objekt-Mapping verursachen Overhead, und Sinkholes noch mehr. |
| Weiterentwickelbarkeit im großen Maßstab | Niedrig | Geringe Kohäsion innerhalb jeder Schicht und Kopplung über Features hinweg machen große Schichtensysteme schwer umzustrukturieren. |
Wann sie gut passt und wann nicht
Die Schichtenarchitektur ist eine gute Wahl für kleine und mittlere Anwendungen, die ein Team baut, für Produkte, deren Domäne noch nicht gut verstanden ist (fachliche Partitionierung braucht Grenzen, die Sie noch nicht kennen), für knappe Budgets und Fristen und für Anwendungen, die überwiegend aus Formularen über Daten mit überschaubaren Regeln bestehen. Sie ist auch eine vernünftige innere Struktur für ein einzelnes Modul oder einen Service, der selbst Teil eines fachlich partitionierten Systems ist: Ein geschichtetes delivery-Modul innerhalb eines modularen Monolithen bekommt das Beste aus beiden Welten.
Als oberste Struktur eines großen Systems mit mehreren Teams ist sie eine schlechte Wahl, weil jedes Team in jeder Schicht arbeitet und Features kollidieren. Sie ist schlecht, wenn Teile des Systems sehr unterschiedliche Skalierbarkeit oder Verfügbarkeit brauchen, weil es nur ein Quantum gibt. Und sie ist schlecht, wenn die Geschäftslogik reichhaltig und zentral ist, weil die Regeln über Controller, Services und Stored Procedures verstreut werden; dort hält eine domänenzentrierte innere Struktur wie hexagonale oder Clean Architecture den Kern unabhängig von der Datenbank und dem Web-Framework.
Der häufigste Entwicklungspfad führt von einem Schichtenmonolithen zu einem modularen Monolithen: ein Deployment behalten, aber die oberste Ebene nach Domänen neu ordnen und die Schichten innerhalb jedes Moduls beibehalten.
Die Schichtenregeln im Code durchsetzen
Schichtenregeln verfallen schnell. Unter Termindruck importiert jemand das Repository direkt in einen Controller, weil das zwanzig Minuten spart, im Review fällt es niemandem auf, und der Nächste kopiert das Muster. Die Abwehr ist ein Architekturtest: eine automatisierte Prüfung von Abhängigkeiten, die im Build läuft und ihn scheitern lässt, wenn eine Regel verletzt wird, wodurch die Regel zu einer Fitness Function wird.
In Python liest import-linter Verträge aus einer Konfigurationsdatei. Sein layers-Vertrag listet die Schichten von der höchsten zur niedrigsten auf und verbietet jeder niedrigeren Schicht, eine höhere zu importieren. Für sich allein macht er die Schichten nicht geschlossen (eine höhere Schicht darf jede niedrigere importieren), daher fügt ein forbidden-Vertrag die Regel hinzu, dass die Präsentation die Persistenz nicht direkt importieren darf; dafür muss allow_indirect_imports eingeschaltet sein, weil sonst die normale Kette von der Präsentation über die Geschäftslogik zur Persistenz als Verstoß zählen würde. In Java drückt ArchUnit dieselben Regeln als Unit-Test aus: layeredArchitecture() deklariert die Schichten nach Paketen und legt zum Beispiel fest, dass auf die Persistenzschicht nur die Serviceschicht zugreifen darf. Ähnliche Werkzeuge gibt es für andere Ökosysteme, etwa dependency-cruiser für JavaScript und TypeScript.
Zwei Praktiken sorgen dafür, dass die Prüfungen wirken. Führen Sie sie mit den vorhandenen Verstößen als bekannte Ausnahmen ein, sodass der Build sofort grün ist und nur neue Verstöße ihn scheitern lassen; bauen Sie die Ausnahmen dann nach und nach ab. Und halten Sie die Konfiguration neben dem Code und prüfen Sie Änderungen daran wie Code, denn eine Regel zu lockern ist eine Architekturentscheidung, die ein Entscheidungsdokument verdient.
[importlinter]
root_package = foodshop
[importlinter:contract:layers]
name = Layers only depend downwards
type = layers
layers =
foodshop.presentation
foodshop.business
foodshop.services
foodshop.persistence
[importlinter:contract:closed-business]
name = Presentation must go through business
type = forbidden
source_modules = foodshop.presentation
forbidden_modules = foodshop.persistence
# presentation -> business -> persistence is the normal path
allow_indirect_imports = TruePrüfen Sie Ihr Verständnis
Was ist der Unterschied zwischen einer geschlossenen und einer offenen Schicht?
Eine Anfrage muss eine geschlossene Schicht durchlaufen und kann sie nicht überspringen; eine offene Schicht darf von der Schicht darüber umgangen werden, was typisch für eine Schicht gemeinsamer Dienste ist, die nur manche Anfragen brauchen.
Warum braucht eine Anwendung in Schichtenarchitektur für ein neues Feature meist Änderungen in jeder Schicht?
Weil sie technisch partitioniert ist: Der Code jeder Geschäftsfähigkeit ist auf Präsentations-, Geschäfts- und Persistenzschicht verteilt, und die meisten Features sind in fachlichen Begriffen definiert.
Was ist der Unterschied zwischen einer Schicht und einem Tier?
Eine Schicht ist eine logische Gruppierung von Code nach Verantwortung; ein Tier ist eine physische Laufzeitgrenze wie ein separater Server. Mehrere Schichten laufen meist innerhalb eines Tiers.
Warum macht ein layers-Vertrag von import-linter die Schichten für sich allein nicht geschlossen?
Er verbietet nur niedrigeren Schichten, höhere zu importieren; eine höhere Schicht darf weiterhin jede niedrigere importieren, daher braucht es einen separaten forbidden-Vertrag, der verhindert, dass die Präsentation die Persistenz importiert.
Quellen und weiterführende Literatur
Haben Sie eine Frage zu diesem Abschnitt? ArchitectBot, der KI-Lernassistent des Kurses, antwortet zuerst aus dem Kurs.
Fragen: „Die meisten unserer Anfragen laufen nur vom Controller über den Service zum Repository, ohne etwas zu tun. Sollten wir die Serviceschicht entfernen?“