Domain Driven Design Tools

Der Blauwal ist ein großartiges Beispiel dafĂŒr, wie das Design eines komplexen Projekts schief gelaufen ist. Der Wal sieht aus wie ein Fisch, ist aber ein SĂ€ugetier: Er fĂŒttert die Jungen mit Milch, er hat Wolle, und die Knochen des Unterarms und der HĂ€nde mit den Fingern sind wie an Land in den Flossen erhalten. Er lebt in den Ozeanen, kann aber unter Wasser nicht atmen und steigt regelmĂ€ĂŸig an die OberflĂ€che, um Luft zu schlucken, auch wenn er schlĂ€ft. Der Wal ist das grĂ¶ĂŸte Tier der Welt, hat die LĂ€nge eines neunstöckigen Hauses und wiegt 75 Volkswagen Touareg-Autos, ist aber kein Raubtier, sondern ernĂ€hrt sich von Plankton.

Als die Entwickler am Wal arbeiteten, fingen sie nicht an, alles von Grund auf neu zu schreiben, sondern nutzten die Erfahrungen aus alten Projekten. Es scheint aus inkompatiblen Teilen des Codes zusammengeschustert zu sein, die nicht getestet wurden, und das gesamte Design bestand darin, ein Framework zu wĂ€hlen und dringend bereits in der Produktion zu „radeln“. Infolgedessen erwies sich das Projekt als wunderschön, aber mit dichtem Erbe und KrĂŒcken unter der Haube.



Um Projekte zu entwickeln, mit denen Unternehmen Geld verdienen können, anstatt wie ein Meerestier auszusehen, das unter Wasser nicht atmen kann, gibt es DDD. Dies ist ein Ansatz, der sich nicht auf Tools oder Code konzentriert, sondern auf das Studium des Themenbereichs, einzelner GeschĂ€ftsprozesse und der Funktionsweise von Code oder Tools fĂŒr die GeschĂ€ftslogik.

Was ist DDD und welche Tools sind darin enthalten? Wir werden in einem Artikel basierend auf dem Bericht erzÀhlenArtyom Malyshev . Der DDD-Ansatz in Python, Tools, Fallstricke, Vertragsprogrammierung und Produktdesign rund um das zu lösende Problem und nicht das verwendete Framework sind unter dem Strich.

VollstÀndige PrÀsentation des Berichts .

Artem Malyshev (Proofit404) - Ein unabhĂ€ngiger Entwickler, der 5 Jahre in Python geschrieben hat, hat aktiv mit Django Channels 1.0 geholfen. SpĂ€ter konzentrierte er sich auf architektonische AnsĂ€tze: Er untersuchte, welche Werkzeuge Python-Architekten fehlen, und startete ein Dry-Python- Projekt . MitbegrĂŒnder von Drylabs.

KomplexitÀt


Was ist Programmierung?
Das Programmieren ist ein stÀndiger Kampf mit der KomplexitÀt, die Entwickler selbst erzeugen, wenn sie versuchen, Probleme zu lösen.
Die KomplexitĂ€t wird in zwei Typen unterteilt: eingefĂŒhrt und natĂŒrlich. Die vorgestellte Version erweitert sich um Programmiersprachen, Frameworks, Betriebssysteme und AsynchronitĂ€tsmodelle. Dies ist eine technische Herausforderung , die nicht fĂŒr Unternehmen gilt. NatĂŒrliche KomplexitĂ€t ist im Produkt verborgen und vereinfacht das Leben der Benutzer - dafĂŒr zahlen die Menschen Geld.
Gute Ingenieure sollten die zusĂ€tzliche KomplexitĂ€t reduzieren und die natĂŒrliche erhöhen, um den Nutzen des Produkts zu erhöhen.
Aber wir Programmierer sind komplexe Leute und wir lieben es, Projekten technische KomplexitÀt zu verleihen. Zum Beispiel haben wir uns nicht mit Codierungsstandards beschÀftigt, keine linternen, modularen Entwurfspraktiken verwendet und in Projekten viel Stilcode erhalten if c==1.

Wie arbeite ich mit solchem ​​Code? Lesen Sie viele Dateien, verstehen Sie Variablen, Bedingungen und wann und wie alles funktionieren wird. Dieser Code ist schwer zu merken - absolut technisch zusĂ€tzliche KomplexitĂ€t.

Ein weiteres Beispiel fĂŒr zusĂ€tzliche KomplexitĂ€t ist meine Lieblings-RĂŒckruf-Hölle.



Wenn wir im Rahmen einer ereignisorientierten Architektur (EDA) schreiben und ein nicht so gutes modernes Rahmenwerk wÀhlen, erhalten wir einen Code, in dem nicht klar ist, was wann passiert. Es ist schwer, einen solchen Code zu lesen - dies ist wiederum die zusÀtzliche KomplexitÀt.

Programmierer lieben nicht nur technische Schwierigkeiten, sondern argumentieren auch, welche besser ist:

  • AsyncIO oder Gevent;
  • PostgreSQL oder MongoDB;
  • Python oder Go;
  • Emacs oder Vim;
  • Tabulatoren oder Leerzeichen;

Die richtige Antwort eines guten Programmierers auf all diese Fragen: "Es macht keinen Unterschied!" Gute Entwickler streiten sich nicht im luftleeren Raum ĂŒber kugelförmige Pferde, sondern lösen geschĂ€ftliche Probleme und arbeiten an der NĂŒtzlichkeit des Produkts. Einige von ihnen haben seit langem eine Reihe von Praktiken etabliert, die die eingefĂŒhrte KomplexitĂ€t reduzieren und Ihnen helfen, mehr ĂŒber das GeschĂ€ft nachzudenken.

Einer von ihnen ist Eric Evans . 2004 schrieb er das Buch Domain Driven Design. Sie „schoss“ und gab den Impuls, mehr ĂŒber das GeschĂ€ft nachzudenken und die technischen Details in den Hintergrund zu rĂŒcken.



Was ist DDD?


Zuerst eine Lösung fĂŒr das Problem und dann Werkzeuge . ZunĂ€chst investierte Evans in das Konzept von DDD, dass dies keine Technologie, sondern eine Philosophie ist. In der Philosophie mĂŒssen Sie zuerst darĂŒber nachdenken, wie Sie das Problem lösen können, und erst dann mit Hilfe der Tools.

Arbeiten Sie mit Fachexperten und Softwareentwicklern an Modellen. Wir mĂŒssen mit Menschen aus der Wirtschaft kommunizieren: Suchen Sie nach einer gemeinsamen Sprache, bauen Sie ein Modell der Welt auf, in der unser Produkt funktioniert, und lösen Sie Probleme.

Schreiben Sie Software, die Modelle explizit ausdrĂŒckt. Der wichtigste Unterschied zwischen DDD und einfacher Zusammenarbeit in einem Team besteht darin, dass wir Software im gleichen Stil schreiben sollten, wie wir mit Domain-Experten sprechen. Alle Begriffe, AnsĂ€tze zur Diskussion und Entscheidungsfindung sollten im Quellcode gespeichert werden, damit auch eine nicht technische Person verstehen kann, was dort passiert.

Sprechen Sie die gleiche Sprache mit dem GeschĂ€ft . DDD ist eine Philosophie, wie man mit GeschĂ€ftsexperten in einem bestimmten Bereich dieselbe Sprache spricht und Terminologie auf diesen Bereich anwendet. Wir haben eine gemeinsame Sprache oder einen gemeinsamen Dialekt innerhalb des gebundenen Kontexts, den wir fĂŒr wahr halten. Wir schaffen Grenzen um architektonische Lösungen.

Bei DDD geht es nicht um Technologie.

Zuerst der technische Teil, dann - DDD. Der Bildhauer, der die Statue aus Stein schnitzt, liest das Handbuch zum Halten von Hammer und Meißel nicht - er weiß bereits, wie man mit ihnen arbeitet. Um DDD in Ihr Projekt zu bringen, beherrschen Sie den technischen Teil: Lernen Sie Django bis zum Ende, lesen Sie das Tutorial und hören Sie auf zu streiten, ob Sie PostgreSQL oder MongoDB verwenden möchten.

Die meisten Entwurfsmuster und -muster sind technisches Rauschen. Die meisten Muster, die wir kennen und verwenden, sind technisch. Sie sagen, wie man Code wiederverwendet, wie man ihn strukturiert, aber sie sagen nicht, wie man ihn fĂŒr Benutzer, Unternehmen und das Modellieren der Außenwelt verwendet. Daher sind Fabriken oder abstrakte Klassen lose an DDD gebunden.

Das erste „blaue“ Buch erschien vor fast 20 Jahren. Die Leute versuchten, in diesem Stil zu schreiben, gingen einen Rechen und stellten fest, dass die Philosophie gut, aber in der Praxis unverstĂ€ndlich ist. Daher erschien ein zweites Buch - "rot" - darĂŒber, wie Programmierer in DDD denken und schreiben.


Die "roten" und "blauen" BĂŒcher sind die SĂ€ulen, auf denen alle DDD stehen.

Hinweis. Die roten und blauen BĂŒcher sind eine einzigartige Informationsquelle ĂŒber DDD, aber sie sind schwer. BĂŒcher sind nicht leicht zu lesen: im Original wegen der komplexen Sprache und Begriffe und auf Russisch wegen der schlechten Übersetzung. Beginnen Sie daher mit einem grĂŒnen Buch , DDD zu lernen . Dies ist eine vereinfachte Version der ersten beiden mit einfacheren Beispielen und allgemeinen Beschreibungen. Aber es ist besser, als wenn die roten und blauen BĂŒcher Ihren Wunsch, DDD zu studieren und anzuwenden, zunichte machen. Es ist besser, das Original einzulesen.

Das rote Buch ĂŒberspringt die Idee, wie DDD am besten in das Projekt einbezogen werden kann und wie die Arbeit um diesen Ansatz herum strukturiert werden kann. Es erscheint eine neue Terminologie - „Model-Driven Design“, bei der unser Modell der Außenwelt an erster Stelle steht.



Die einzige Ortstechnologie, die ausgewĂ€hlt wird, ist Smart UI. Dies ist eine Schicht zwischen der Außenwelt, dem Benutzer und uns (ein Hinweis auf Robert Martin und seine saubere Architektur mit Schichten). Wie Sie sehen können, geht alles zum Modell.

Was ist ein Modell? Dies ist der Phantomschmerz eines jeden Architekten. Jeder denkt, das ist UML, aber das ist es nicht.
Ein Modell besteht aus einer Reihe von Klassen, Methoden und VerknĂŒpfungen zwischen ihnen, die die GeschĂ€ftsszenarien im Programm widerspiegeln.
Das Modell spiegelt ein reales Objekt mit allen notwendigen Eigenschaften und Funktionen wider. Dies ist ein Toolkit auf hoher Ebene, mit dem Entscheidungen aus Sicht von GeschĂ€ftsfĂ€llen getroffen werden können. Methoden und Klassen sind jedoch ein einfaches Toolkit fĂŒr Architekturlösungen.

Trockene Python


Um die Modellnische zu fĂŒllen, habe ich ein Dry-Python- Projekt gestartet , das sich zu einer Sammlung hochrangiger Architekturbibliotheken fĂŒr das Erstellen von Model Driven Design entwickelt hat. Jede der Bibliotheken versucht, einen Kreis in der Architektur zu schließen und stört den anderen nicht. Bibliotheken können einzeln oder zusammen verwendet werden, wenn Sie einen Geschmack bekommen.



Die Reihenfolge der ErzĂ€hlung entspricht der Chronologie der optimalen HinzufĂŒgung von DDD zum Projekt - nach Schichten. Die erste Schicht sind Services , eine Beschreibung der GeschĂ€ftsszenarien (Prozesse) in unserem System. Die Stories-Bibliothek ist fĂŒr diese Ebene verantwortlich.

Geschichten


GeschÀftsszenarien sind in drei Teile unterteilt:

  • Spezifikation - eine Beschreibung des GeschĂ€ftsprozesses;
  • Der Zustand, in dem das GeschĂ€ftsszenario existieren kann
  • Implementierung jedes Schritts des Skripts.

Diese Teile dĂŒrfen nicht gemischt werden. Die Stories-Bibliothek trennt diese Teile und zeichnet eine klare Linie zwischen ihnen.

Betrachten Sie die EinfĂŒhrung von DDD und Stories anhand eines Beispiels. Zum Beispiel haben wir ein Projekt ĂŒber Django mit einer Mischung aus Django-Signalen und obskuren „dicken“ Modellen. FĂŒgen Sie ein leeres Servicepaket hinzu. Mit der Stories-Bibliothek in Teilen schreiben wir diesen Hash in einen klaren und verstĂ€ndlichen Satz von Skripten in unserem Projekt um.

DSL-Spezifikation. In der Bibliothek können Sie eine Spezifikation schreiben und hierfĂŒr DSL bereitstellen. Auf diese Weise können Benutzeraktionen Schritt fĂŒr Schritt beschrieben werden. Zum Kaufen subscriptionfolge ich zum Beispiel mehreren Schritten: Ich finde eine Bestellung, ĂŒberprĂŒfe die Relevanz des Preises und prĂŒfe, ob der Benutzer es sich leisten kann. Dies ist eine allgemeine Beschreibung.

Vertrag.Unterhalb dieser Klasse schreiben wir einen Vertrag ĂŒber den Stand des GeschĂ€ftsszenarios. Zu diesem Zweck bezeichnen wir den Bereich der Variablen, die im GeschĂ€ftsprozess auftreten, und weisen jeder Variablen eine Reihe von Validatoren zu.

Sobald jemand versucht, diesem Bereich im Rahmen des GeschĂ€ftsprozesses eine Variable zuzuweisen, wird eine Reihe von Validatoren ausgearbeitet. Wir werden sicher sein, dass der Status des Prozesses zur Laufzeit immer funktioniert. Aber wenn nicht, fĂ€llt es schmerzhaft und schreit laut darĂŒber.

Umsetzungsphase jedes Schritts . In derselben Klasse subscriptionschreiben wir eine Reihe von Methoden, deren Namen GeschĂ€ftsschritten entsprechen. Jede Eingabemethode erhĂ€lt einen Status, mit dem sie arbeiten kann, hat jedoch nicht das Recht, sie zu Ă€ndern. Die Methode gibt möglicherweise einen Marker zurĂŒck und meldet:

  • , () ;
  • - , .


Es gibt komplexere Markierungen: Sie können bestÀtigen, dass der Status funktioniert, einige Teile des GeschÀftsprozesses löschen oder Àndern. Sie können auch in Klassen schreiben.

Story starten. Wie starte ich Story bei der AusfĂŒhrung? Dies ist ein GeschĂ€ftsobjekt, das als Methode funktioniert: Wir ĂŒbertragen Daten an die Eingabe, validieren sie und interpretieren die Schritte. Die laufende Story merkt sich den AusfĂŒhrungsverlauf, zeichnet den Status auf, der im GeschĂ€ftsprozess darin aufgetreten ist, und gibt an, wer diesen Status beeinflusst hat .

Debug-Symbolleiste. Wenn wir in Django schreiben und das Debug-Panel verwenden, können wir sehen, welche GeschÀftsszenarien in jeder Anfrage verarbeitet wurden und welchen Status sie haben.

Py.test. Wenn wir in py.test schreiben, können wir fĂŒr den gefallenen Test sehen, welche GeschĂ€ftsskripte in jeder Zeile ausgefĂŒhrt wurden und was schief gelaufen ist. Dies ist praktisch - anstatt den Code einzugeben, lesen wir die Spezifikation und verstehen, was passiert ist.



Wache. Noch besser, wenn wir den Fehler 500 erhalten. In einem regulĂ€ren System lassen wir uns damit ab und beginnen zu untersuchen. In Sentry wird ein detaillierter Bericht darĂŒber angezeigt, was der Benutzer getan hat, um den Fehler zu machen. Es ist bequem und angenehm, wenn um 3 Uhr morgens solche Informationen fĂŒr Sie gesammelt wurden.


ELK . Jetzt arbeiten wir aktiv an einem Plugin, das all dies in Elasticsearch in den Kibana-Stack schreibt und kompetente Indizes erstellt.



Zum Beispiel haben wir einen Vertrag ĂŒber den Status eines GeschĂ€ftsprozesses. Wir wissen zum Beispiel, was da istrelation IDBericht. Anstatt archaisch zu recherchieren, was einst dort passiert ist, schreiben wir eine Anfrage in Kibana. Es werden alle Geschichten angezeigt, die sich auf einen bestimmten Benutzer beziehen. Als nĂ€chstes untersuchen wir den Zustand innerhalb unserer GeschĂ€ftsprozesse und GeschĂ€ftsszenarien. Wir schreiben keine einzige Zeile Protokollierungscode, aber das Projekt wird auf der Abstraktionsebene protokolliert, auf der wir es sehen möchten.

Aber ich möchte etwas Höheres, zum Beispiel leichte Objekte. Solche Objekte enthalten gebildete Datenstrukturen und -methoden, die sich auf die Annahme von GeschÀftsentscheidungen beziehen und beispielsweise nicht auf die Arbeit mit der Datenbank. Daher fahren wir mit dem nÀchsten Teil der modellgetriebenen Architektur fort - EntitÀten, Aggregate und Wertobjekte.



EntitÀten, Aggregate und Wertobjekte


Wie ist das alles miteinander verbunden? Zum Beispiel gibt ein Benutzer eine Produktbestellung auf und wir berechnen. Was ist die Wurzel der Aggregation und was ist ein einfaches Objekt?



Alles, was unterstrichen wird, ist die Wurzel der Aggregation. Damit möchte ich direkt arbeiten: wichtig, wertvoll, ganzheitlich.

Wo soll ich anfangen? Wir werden im Projekt ein leeres Paket erstellen, in das wir unsere Einheiten stellen. Aggregate werden besser mit etwas Deklarativem wie dataclassesoder geschrieben attrs.

Datenklassen . Wenn dataclasswir eine Art Aggregat angeben, schreiben wir mit NewType eine Anmerkung dazu . In der Anmerkung geben wir eine explizite Referenz an, die im Typsystem ausgedrĂŒckt wird. Wenn es sich dataclassnur um eine Datenstruktur (EntitĂ€t) handelt, speichern Sie sie im Aggregat.

Im Kontext von Geschichten können nur Aggregate lĂŒgen. Der Zugriff auf etwas, das in sie eingebettet ist, kann nur ĂŒber öffentliche Methoden und Regeln auf hoher Ebene erfolgen. Auf diese Weise können Sie logisch und kompetent ein Modell erstellen, ĂŒber das wir mit Experten aus dem Fachgebiet zusammenarbeiten. Dies ist dieselbe einzelne Sprache .



Das Problem tritt sofort auf - Repositories. Ich habe eine Datenbank, mit der ich ĂŒber Django arbeite, einen nahe gelegenen Microservice, an den ich Anfragen sende. Es gibt JSON und eine Instanz des Django-Modells. Daten empfangen und von Hand ĂŒbertragen, nur um die Methode schön aufzurufen oder zu testen? Nein, natĂŒrlich. Dry-Python verfĂŒgt ĂŒber eine Mappers-Bibliothek, mit der Sie Abstraktionen und DomĂ€nenaggregate auf hoher Ebene den Orten zuordnen können, an denen wir sie speichern.

Mapper


Wir fĂŒgen unserem Projekt ein weiteres Paket hinzu - ein Repository, in dem wir unser speichern werden mappers. Auf diese Weise ĂŒbertragen wir GeschĂ€ftslogik auf hoher Ebene in die reale Welt.

Zum Beispiel können wir beschreiben, wie wir eines dataclasseinem Django-Modell zuordnen.

Django ORM. Wir vergleichen das Bestellmodell mit der Beschreibung von Django ORM - wir betrachten die Felder.

Zum Beispiel können wir einige Felder ĂŒber die optionale Konfiguration neu schreiben. Folgendes wird passieren: mapperWĂ€hrend der Deklaration wird verglichen, wie das dataclassModell geschrieben wird . Beispielsweise entsprechen Anmerkungen int(in Order dataclasseinem Feld costmit Anmerkungen int) im Django-Modell integer fieldder Option nullable="true". Hier wird es dataclassbieten hinzufĂŒgen optionalzu dataclass, oder zu entfernennullablevon field.

Über Mappers können Sie Funktionen hinzufĂŒgen, die etwas lesen oder schreiben. Leser sind Funktionen, die am Eingang ein Aggregat empfangen und einen Verweis darauf zurĂŒckgeben. Autoren machen das Gegenteil - Einheiten zurĂŒckgeben. Unter der Haube kann beispielsweise eine Anfrage an die Datenbank ĂŒber Django erfolgen.

Swagger Definitionen Die gleichen Operationen können mit Microservices durchgefĂŒhrt werden. Sie können einen Teil des Swagger-Schemas darauf schreiben und ĂŒberprĂŒfen, inwieweit das Swagger-Schema eines bestimmten Dienstes mit Ihren Domain-Modellen ĂŒbereinstimmt. Außerdem wird die zurĂŒckgegebene Anforderung aus der Anforderungsbibliothek transparent in ĂŒbersetzt dataclass.

GraphQL-Abfragen. GraphQL und Microservices: Das Schema des GraphQL-Schnittstellentyps funktioniert gut dagegendataclass. Sie können bestimmte GraphQL-Abfragen in interne Datenstrukturen ĂŒbersetzen.

Warum sollten Sie sich mit dem internen Datenmodell auf hoher Ebene in der Anwendung beschĂ€ftigen? Um das „Warum“ zu veranschaulichen, werde ich eine „unterhaltsame“ Geschichte erzĂ€hlen.

In einem unserer Projekte arbeiteten Web-Sockets ĂŒber den Pusher-Service. Wir haben uns nicht darum gekĂŒmmert, wir haben es in eine Schnittstelle eingewickelt, um nicht direkt anzurufen. Diese Schnittstelle war in allen Geschichten gebunden und war zufrieden.

Die geschĂ€ftlichen Anforderungen haben sich jedoch geĂ€ndert. Es stellte sich heraus, dass die Garantien, die Pusher fĂŒr Web-Sockets bietet, nicht ausreichen. Beispielsweise benötigen Sie eine garantierte NachrichtenĂŒbermittlung und einen garantierten Nachrichtenverlauf fĂŒr die letzten 2 Minuten. Aus diesem Grund haben wir uns fĂŒr den Ably Realtime-Service entschieden. Es hat auch eine Schnittstelle - wir werden einen Adapter schreiben und ihn ĂŒberall binden, alles wird großartig. Nicht wirklich.

Die von Pusher verwendeten Abstraktionen (Funktionsargumente) sind in jedem GeschÀftsobjekt eingeschlossen. Ich musste ungefÀhr 100 Geschichten reparieren und die Bildung des Benutzerkanals korrigieren, an den wir etwas senden.

ZurĂŒck zu den Tests.

Tests & Mocks


Wie testen Sie dieses Verhalten normalerweise mit externen Diensten? Wir machen etwas nass, wir beobachten, wie eine Bibliothek eines Drittanbieters aufgerufen wird, und das ist alles - wir sind sicher, dass alles in Ordnung ist. Wenn sich die Bibliothek Àndert, Àndern sich auch die Argumentformate.

Sie können eine Woche sparen, indem Sie Tausende von Tests und Hunderte von GeschĂ€ftsfĂ€llen neu schreiben, wenn Sie das Verhalten des internen Modells anders testen. Zum Beispiel Ă€hnlich wie beim Integrationstest: Wir schreiben in den Benutzer-Stream und ĂŒbersetzen diesen Stream bereits im Adapter, Pusher oder Ably in den Namen des normalen Kanals, um nicht alles in die GeschĂ€ftslogik zu schreiben.

AbhÀngigkeiten


In einer solchen Modellarchitektur erscheinen viele ĂŒberflĂŒssige EntitĂ€ten. Zuvor haben wir eine Art Django-Funktion ĂŒbernommen und geschrieben: Anfrage, Antwort, minimale Körperbewegungen. Hier mĂŒssen Sie die Mapper initialisieren, Stories eingeben und initialisieren, die Anforderungszeile der HTTP-Anforderung verarbeiten und sehen, welche Antwort Sie geben mĂŒssen. All dies fĂŒhrt zu 30-50 Zeilen Boilerplate-Aufrufcode-Geschichten in der Django-Ansicht.

Andererseits haben wir bereits Schnittstellen und Mapper geschrieben. Wir können ihre KompatibilitĂ€t mit einem bestimmten GeschĂ€ftsfall ĂŒberprĂŒfen, beispielsweise mithilfe der AbhĂ€ngigkeitsbibliothek. Wie? Durch das AbhĂ€ngigkeitsinjektionsmuster wird alles deklarativ auf eine minimale Kesselplatte geklebt.

Hier geben wir die Aufgabe an, eine Klasse in das Servicepaket aufzunehmen, setzen Sie dreimappers, initialisiere das Stories-Objekt und gib es uns. Mit diesem Ansatz wird die Anzahl der Boilerplates im Code enorm reduziert.

Refactoring-Karte


Mit allem, worĂŒber ich gesprochen habe, haben wir ein Schema entwickelt, mit dem wir ein großes Projekt von Django-Signalen (implizite "RĂŒckruf-Hölle") mit DDD nach Django umgeschrieben haben.

Der erste Schritt ohne DDD . Zuerst hatten wir kein DDD - wir haben MVP geschrieben. Als sie ihr erstes Geld verdienten, luden sie Investoren ein und ĂŒberzeugten sie, zu DDD zu wechseln.

Geschichten ohne VertrÀge. Wir haben das Projekt in logische GeschÀftsfÀlle ohne DatenvertrÀge unterteilt.

VertrĂ€ge und Aggregate . Anschließend haben wir nacheinander den Datenvertrag fĂŒr jedes Modell gezogen, der in unserer Architektur nachverfolgt werden kann.

Mapper . Mappers haben geschrieben, um Data Warehouse-Vorlagen loszuwerden.

AbhÀngigkeitsinjektion . Klebemuster loswerden.

Wenn Ihr Projekt aus MVP herausgewachsen ist und dringend in der Architektur geĂ€ndert werden muss, damit es nicht in das Erbe ĂŒbergeht, schauen Sie in Richtung DDD.

legacy Python-, , , Moscow Python Conf++ 27 . Python . unconference, , , , Drylabs.

DDD Python, TechLead Conf — IT-, DDD . 8 , Call for Papers 6 .

All Articles