EinfĂŒhrung
In frĂŒheren Artikeln haben wir den Umfang des Ansatzes identifiziert und die grundlegenden methodischen Prinzipien des Domain Driven Design untersucht .
In diesem Artikel möchte ich die wichtigsten modernen AnsĂ€tze zum Aufbau der Architektur von Unternehmenssystemen skizzieren: Supple, Screaming, Clean und meine klare Interpretation in Form einer schlĂŒsselfertigen Komplettlösung geben.

In Zukunft werden wir jedes Entwurfsmuster im Detail betrachten: Wir geben den Umfang an, geben Codebeispiele an und heben empfohlene Vorgehensweisen hervor. Als Ergebnis werden wir einen vorgefertigten Microservice schreiben.
Flexible Architektur
Im letzten Artikel haben wir uns auf die Tatsache konzentriert, dass DDD die Praxis der Implementierung durch das Modell beinhaltet. Der Themenbereich sollte durch Ihren Code beschrieben werden. Versuchen wir herauszufinden, wie das geht.
Eric Evans bietet in seinem Buch eine Reihe empfohlener Entwurfsmuster und bezeichnet diesen Ansatz als flexibel:
Im Namen der ArchitekturflexibilitĂ€t wurden viele unnötige Konstruktionen in Programmen angehĂ€uft. ĂbermĂ€Ăige Abstraktionsebenen und indirekte VerknĂŒpfungen stören eher als helfen in dieser Angelegenheit. Schauen Sie sich die Architektur an, die Programmierer wirklich dazu inspiriert, sie zu verfeinern, und Sie werden normalerweise etwas sehr Einfaches sehen. Einfach heiĂt aber nicht einfach auszufĂŒhren. Um solche Elemente zu schaffen, die zu komplexen Systemen zusammengesetzt werden können und gleichzeitig leicht zu verstehen sind, ist es notwendig, "Engagement" fĂŒr das Entwerfen nach dem Modell mit einem ziemlich strengen Architekturstil zu kombinieren. Eine bestimmte DesignfĂ€higkeit ist nicht nur erforderlich, um etwas zu erstellen, sondern auch, um das fertige zu verwenden.
Eric Evans, Domain-Driven Design: KomplexitÀt im Herzen von Software angehen
Die vorgestellten Entwurfsmuster sind keine strenge Architektur oder vorgefertigte Lösung, sondern DenkanstöĂe.
AuffÀllige Architektur
Ăhnliche Gedanken kamen in den Köpfen vieler Entwickler und Designer komplexer Systeme auf.
Im Jahr 2011 wurde ein Artikel von Robert Martin - Screaming Architecture veröffentlicht, der besagt, dass Ihr Code den Themenbereich nicht nur beschreiben, sondern vorzugsweise obszön darĂŒber schreien sollte.
Was schreit die Architektur Ihrer Anwendung? Wenn Sie sich die Verzeichnisstruktur der obersten Ebene und die Quelldateien im Paket der höchsten Ebene ansehen. schreien sie: Gesundheitssystem oder Buchhaltungssystem oder Bestandsverwaltungssystem? Oder schreien sie: Rails oder Spring / Hibernate oder ASP?
Robert C. Martin, 30. September 2011
Robert sagt, dass Ihr Anwendungscode die AktivitĂ€t der Anwendung widerspiegeln sollte, anstatt sich an die Regeln des Frameworks anzupassen. Die Framework-Struktur sollte Ihre Architektur nicht einschrĂ€nken. Die Anwendung sollte wiederum nicht an die Datenbank oder das http-Protokoll angehĂ€ngt werden. Dies sind lediglich Speicher- und Ăbermittlungsmechanismen. Der Begrenzungsrahmen ist ein Werkzeug. Sie sollten kein AnhĂ€nger des Frameworks werden. Die Tests Ihrer Anwendung sind Tests der Funktionslogik und keine Tests des http-Protokolls.
Saubere Architektur
Ein Jahr spÀter der nÀchste Artikel von Robert Martin - The Clean Architecture . Darin erklÀrt der Autor, wie man den Code zum Schreien bringt. Nachdem er mehrere Architekturen studiert hat, identifiziert er die Grundprinzipien:
- RahmenunabhÀngigkeit. Die Architektur ist nicht von einer vorhandenen Bibliothek abhÀngig. Auf diese Weise können Sie Frameworks als Werkzeuge verwenden und nicht die EinschrÀnkungen, die Ihre HÀnde binden.
- Testbarkeit. GeschÀftsregeln können ohne BenutzeroberflÀche, Datenbank, Webserver oder andere technische Mittel getestet werden.
- UnabhÀngigkeit der BenutzeroberflÀche. Die BenutzeroberflÀche kann einfach geÀndert werden, ohne den Rest des Systems zu Àndern. Beispielsweise kann die WeboberflÀche durch die Konsolenschnittstelle ersetzt werden, ohne die GeschÀftslogik zu Àndern.
- DatenbankunabhÀngigkeit. Sie können Oracle oder SQL Server gegen Mongo, BigTable, CouchDB oder etwas anderes austauschen. Ihre Anwendungslogik sollte nicht datenbankgebunden sein.
- UnabhĂ€ngigkeit von UmwelteinflĂŒssen. TatsĂ€chlich wissen Ihre GeschĂ€ftsregeln einfach nichts ĂŒber die AuĂenwelt.
Auf einem habr wurde bereits ein sehr guter Artikel Misconceptions Clean Architecture veröffentlicht . Sein Autor Jeevuz hat die Feinheiten des VerstÀndnisses dieses Ansatzes sehr gut gekaut. Ich empfehle Ihnen dringend, sich sowohl mit ihm als auch mit den Originalmaterialien vertraut zu machen.
Variable Architektur
Die Beschreibung des obigen Ansatzes sieht nicht so einfach aus. Im Rahmen der Entwicklung der Architektur einer Reihe komplexer Unternehmenssysteme haben meine Kollegen und ich eine ziemlich klare Interpretation der beschriebenen AnsÀtze entwickelt, die ich im Folgenden vorstellen möchte.
Vor dem Aufkommen von Computern und Programmiersprachen wurde der Papierworkflow verwendet, um Systeme mit komplexer GeschÀftslogik zu erstellen und zu verwalten. Das Ergebnis eines Prozesses war ein Dokument, das letztendlich ein bestimmtes GeschÀftsobjekt beschrieb. Infolgedessen bestand der Papierkram aus drei einfachen Aktionen :
- Dokumenterstellung
- Dokumentenverarbeitung
- Arbeiten Sie mit dem Archiv der Dokumente
- Einreichung von Dokumenten
Dokument - Aufzeichnen von Informationen ĂŒber wirtschaftliche AktivitĂ€ten eines bestimmten realen GeschĂ€ftsobjekts.
Bitte beachten Sie, dass das Dokument selbst kein echtes GeschÀftsobjekt ist, sondern nur sein Modell . Derzeit werden Papierdokumente durch elektronische Dokumente ersetzt. Ein Dokument kann eine Aufzeichnung in einer Tabelle, einem Bild, einer Datei, einem gesendeten Brief oder einer anderen Information sein.
Ich möchte das Word-Dokument in Zukunft nicht mehr verwenden, da es verwirrender sein wird, werden wir das Konzept der EntitĂ€t aus der DDD-Terminologie verwenden. Sie können sich jedoch vorstellen, dass Ihr gesamtes System jetzt ein elektronisches Dokumentenverwaltungssystem ist, das vier einfache Aktionen ausfĂŒhrt.
- Sammeln
- Verarbeitung
- Lagerung
- ReprÀsentativeation
Aktion - eine strukturelle AktivitĂ€tseinheit eines GeschĂ€ftsmodells; ein relativ abgeschlossener separater Akt eines bewussten Ziels, die WillkĂŒr und IntentionalitĂ€t der individuellen AktivitĂ€t eines GeschĂ€ftsobjekts, die vom Endbenutzer unterschieden wird.
Ein gutes Beispiel fĂŒr Action ist ein Theaterakt. Das Theater modelliert Ereignisse aus dem wirklichen Leben. Die Handlung ist ein bedeutender Teil des StĂŒcks. Um die Geschichte zu vervollstĂ€ndigen, mĂŒssen Sie jedoch mehrere Akte in einer genau festgelegten Reihenfolge spielen. Eine solche Reihenfolge in unserer Architektur werden wir den Modus nennen .
Modus (Leitung) - Eine Reihe von Aktionen in einer bestimmten Reihenfolge, die eine vollstĂ€ndige Bedeutung haben und fĂŒr den Endbenutzer von Vorteil sind.

FĂŒr solche Betriebsarten wurde ein selektiver Leiter oder Selektor erfunden. Genauer gesagt, "Zeitsteuerungsmechanismus zum DurchfĂŒhren eines ausgewĂ€hlten aus einer Vielzahl von Betriebssequenzen", fĂŒr die das Patent US2870278A erhalten wurde. Wir kennen dieses GerĂ€t als die "Drehung" der Waschmaschine. Die architektonische Wendung wird am Anfang des Artikels angegeben.
Die VariabilitĂ€t des Ansatzes zeigt sich in der Tatsache, dass Sie mit dieser Architektur einen der vier Modi auswĂ€hlen können, bei denen Sie keine unnötigen Aktionen ausfĂŒhren.
Beim Starten der Waschmaschine können Sie den Modus auswĂ€hlen: Waschen, SpĂŒlen oder Schleudern. Wenn Sie sich fĂŒr das Waschen entscheiden, spĂŒlt Ihre Maschine die WĂ€sche trotzdem aus und drĂŒckt sie dann zusammen. Mit der SpĂŒlung im Kit werden Sie sicher einen Spin bekommen. Schleudern - die letzte Aktion im Waschprozess ist die âeinfachsteâ. In unserer Architektur ist die einfachste Aktion die ReprĂ€sentation , und wir werden damit beginnen.
Vertretung
Wenn wir von einer reinen PrĂ€sentation sprechen, ohne auf eine Datenbank oder eine externe Quelle zurĂŒckzugreifen, geben wir einige statische Informationen aus: eine HTML-Seite, eine Datei, ein Verzeichnis in Form von json. Wir können sogar nur eine Code-Antwort ausgeben - 200:
Schreiben wir den einfachsten "Health Checker"
module Health class Endpoints < Sinatra::Base get '/check' do; end end end
In seiner primitivsten Form wird unser Schema folgendermaĂen aussehen:

Lyrischer ExkursIch bitte Sie zu beachten, dass im Sinatra-Framework die Endpoints- Klasse sowohl Router als auch Controller in einer Klasse kombiniert. VerstöĂt dies gegen den Grundsatz der alleinigen Verantwortung? TatsĂ€chlich ist Endpoints keine Klasse, sondern eine Ebene, die durch eine Klasse und ihren Verantwortungsbereich auf einer höheren Ebene ausgedrĂŒckt wird.
Ok, was ist mit Router und Controller ? Sie werden nicht durch eine Reihe von Klassen dargestellt, sondern durch den Namen und die Implementierung einer Funktion. Eine statische Datei ist im Allgemeinen eine Datei. Eine Klasse ist fĂŒr eine Verantwortung verantwortlich, aber versuchen Sie nicht, jede Verantwortung durch eine Klasse auszudrĂŒcken. Verwenden Sie PraktikabilitĂ€t, nicht Dogmatismus.
Arbeiten Sie mit dem Speichersystem
Unternehmen fordern die VerfĂŒgbarkeit Ihrer Anwendung. Warum sollte jemand Ihren Service benötigen, wenn wir ihn nicht zum richtigen Zeitpunkt nutzen können? Um die DatenintegritĂ€t sicherzustellen, zeichnen wir nach jeder Verarbeitung eine Ănderung des Status eines GeschĂ€ftsobjekts auf.
Zum Abrufen eines Objekts aus dem Speicher ist kein Zugriff auf die GeschĂ€ftslogik erforderlich. Stellen Sie sich vor, wir automatisieren die AktivitĂ€ten einer Hotelkette und haben ein Gastmagazin an der Rezeption. Wir haben uns entschlossen, Informationen ĂŒber den Besucher zu sehen.
module Reception class Endpoints < Sinatra::Base
Arbeiten Sie mit dem Speichersystem in Form eines grafischen Diagramms:

Wie wir sehen können, wird die Kommunikation zwischen der fĂŒr das Speichern verantwortlichen Schicht und der fĂŒr die Darstellung von Daten verantwortlichen Schicht ĂŒber das Antwortmodell implementiert. Dieses Modell gehört zu keiner dieser Ebenen. TatsĂ€chlich ist dies ein GeschĂ€ftsobjekt und befindet sich auf der Ebene, die fĂŒr die GeschĂ€ftslogik verantwortlich ist.
Verarbeitung
Wenn sich das Objektmodell aufgrund seiner Eigenschaften Ă€ndert, ohne neue Daten einzufĂŒhren, wenden wir uns direkt der Interactor- Ebene zu. Die Interactor- Schicht ist der SchlĂŒssel in unserer Anwendung. Sie beschreibt die gesamte GeschĂ€ftslogik in Form separater AnwendungsfĂ€lle und Ă€ndert sich darauf.
Betrachten Sie diesen Anwendungsfall. Der Besucher ist bereits in unserem Hotel registriert, aber wir feiern jede Ankunft oder Abreise.
module Reception class Endpoints < Sinatra::Base
Lass uns ein bisschen aufhören. Warum nicht die Implementierung zu einer einzigen Methode mit dem status
? Die Interaktoren fĂŒr Arrival
und Departure
unterscheiden sich grundlegend. Wenn ein Gast zu uns kommt, mĂŒssen wir prĂŒfen, ob die Reinigung beendet ist, ob neue Nachrichten fĂŒr ihn eingegangen sind usw. Im Gegenteil, bei seiner Abreise mĂŒssen wir gegebenenfalls die Reinigung einleiten. Im Gegenzug erinnern wir uns nicht einmal an die Nachrichten, denn wenn er in einem Hotel gewesen wĂ€re, hĂ€tten wir ihn sofort angerufen. Es ist all diese GeschĂ€ftslogik, die wir auf der Interactor- Ebene vorschreiben.

Aber was sollen wir tun, wenn wir Daten von auĂen haben? Hier ist die Aktion der Datenerfassung verbunden.
Daten sammeln
Bei der erstmaligen Anmeldung eines Gastes im Hotel fĂŒllt er das Anmeldeformular aus. Dieses Formular wird ĂŒberprĂŒft. Wenn die Daten korrekt sind, findet der GeschĂ€ftsprozess Registrierung statt. Der Prozess gibt Daten zurĂŒck - das erstellte GeschĂ€ftsmodell "Mandant". Wir prĂ€sentieren dem Gast dieses Modell in lesbarer Form:
module Reception class Endpoints < Sinatra::Base
Schematisch sieht es so aus:

Spielregeln (Regeln)
- In Bezug auf Prozesse ist ein variatives System in Aktionen unterteilt .
- Die Reihenfolge der Aktionen wird durch den Modus bestimmt .
- Die Modi sind inkrementell.
- Ein âkomplexererâ Modus ergĂ€nzt einen âeinfacherenâ Modus fĂŒr nur eine Aktion.
- Jede Aktion findet im Rahmen einer Ebene statt .
- Jede Ebene wird durch eine Klasse dargestellt .
- Innerhalb einer Ebene können sich Ebenenklassen und Verantwortungsklassen befinden .
- Die Kommunikation findet nur zwischen der Schicht und der Zwischenschichtklasse statt.
- Darstellungsmodelle sind Ausnahmen.
- Die Fehlerbehandlung sollte auf Klassenebene erfolgen .

Allgemeines Schema
Dieser Ansatz hat eine hohe Eintrittsschwelle. Die Anwendung erfordert viel Erfahrung des Designers, um die zu lösenden Aufgaben klar zu verstehen. Die KomplexitÀt reprÀsentiert auch die Vielfalt der Auswahlmöglichkeiten des erforderlichen Werkzeugs. Trotz der KomplexitÀt der Struktur ist die Implementierung auf Codeebene unglaublich einfach und ausdrucksstark. Obwohl es eine Reihe von Konventionen und Vollmachten enthÀlt. In Zukunft werden wir jede Entwurfsvorlage einzeln analysieren, beschreiben, wie sie erstellt, getestet und der Umfang festgelegt wird. Und um nicht in ihrer Vielfalt verwirrt zu werden, wird eine vollstÀndige Karte angeboten:

Hochauflösende Karte