Bei TDD geht es darum, Code anhand von Tests zu entwerfen.
Daher werden typische Schichten normalerweise nicht im Voraus aufgebaut. Sie sollten leicht durch Refactoring-Schritte angezeigt werden.
Das domänengetriebene Design umfasst viele technische Muster, die gut etablierte Schichten wie die Anwendungsschicht, die Infrastrukturschicht, die Domänenschicht und die Persistenzschicht definieren.
Wie verhält man sich, um den Codierungsteil eines DDD-Projekts von Grund auf neu zu starten?
Sollte ich das Design strikt aus Tests hervorgehen lassen, dh keine Trennung von Bedenken (keine Schichten) und Refaktor, um es an die technischen Muster von DDD anzupassen?
Oder sollte ich diese leeren Ebenen (Anwendung, Entitäten / Domänendienste, Infrastruktur) erstellen und TDD unabhängig voneinander in jede Ebene einpassen lassen (indem ich Mocks verwende, um zwischen den Ebenen zu isolieren)?
Antworten:
Lesen Sie unbedingt die jüngsten Kommentare von Onkel Bob zur Rolle des Designs in TDD .
Udi Dahan: "Gott, wie ich es hasse, zu schichten." Er verbringt einige Zeit damit, es in seinem Vortrag CQRS zu diskutieren - aber anders (Layering beginnt um 18:30 Uhr)
Ich würde Ihren Satz etwas anders buchstabieren; „DDD erkennt , dass es eine Reihe von Bedenken in den meisten Geschäftsanwendungen ist und dass die Lösungen auf diese Bedenken haben unterschiedliche Lebenszeiten“ .
Beispielsweise müssen Domain-Belange in der Regel flexibel sein - insbesondere, wenn Sie eine Lösung für ein bestimmtes Unternehmen anpassen. Schließlich geht es bei der Domäne darum, wie das Unternehmen Geschäfte tätigt, dh wie das Unternehmen Geld verdient und in der Lage ist, schnell Geschäftsverbesserungen zu erzielen, und dies sind die freien Einnahmen.
Andererseits müssen Sie die Persistenzkomponente wahrscheinlich nicht häufig ändern. Die Datenbanklösung, die im letzten Release funktioniert hat, funktioniert wahrscheinlich auch in diesem Release.
Die Anwendungsprobleme liegen irgendwo in der Mitte. Sie sind in der Regel stabil, sodass die Benutzer nicht mit jeder Version eine neue App erlernen müssen.
Es kann auch mehrere Implementierungen geben, um ein bestimmtes Problem zu lösen. Beispielsweise benötigt die Anwendung möglicherweise nur einen Schnappschuss ihres aktuellen Status - es reicht aus, eine Datei auf der Festplatte zu speichern. Und in den ersten paar Iterationen ist dies möglicherweise auch alles, was die Domäne benötigt. Aber irgendwann kommt eine Geschichte, die Unterstützung für Ad-hoc-Abfragen erfordert, und Sie erkennen, dass die Konfiguration einer relationalen Datenbank viel einfacher ist als die Implementierung einer neuen Datenbank. Und dann gibt es noch eine Funktion, die in einer Grafikdatenbank besser funktioniert.
In der Zwischenzeit möchte der CTO eine Version der App, die auf seinem Telefon ausgeführt wird. Der CEO hörte gerade von einem Mann, dass die Veröffentlichung einer API die große Sache ist.
Außerdem verwendet das Verkaufsteam ein anderes Modell. Geben Sie uns daher dieselbe App mit einem anderen Modell. Oh, aber wir sind viel unterwegs, daher muss unsere Version funktionieren, wenn wir offline sind und später synchronisieren ...
Mit anderen Worten, wenden Sie die taktischen Muster von ddd nicht durch leere Platzhalter Implementierung und unter der Annahme , werden sie in später gefüllt werden, sondern durch die Anerkennung , wenn Sie die Bäche überqueren „Hey, dass Beharrlichkeit Code in meinem Domain - Modell, ich muss nicht sein Refactoring noch nicht abgeschlossen. "
quelle
Test Driven Development (TDD) ist kein Design. Dies ist eine Anforderung, die sich auf Ihr Design auswirkt. Genau so, als müssten Sie threadsicher sein, das ist kein Design. Auch dies ist eine Anforderung, die sich auf Ihr Design auswirkt.
Wenn Sie fröhlich alle anderen Designprobleme ignorieren und die TDD-Regeln religiös einhalten, machen Sie TDD nicht dafür verantwortlich, wenn sich Ihr Code in Mist verwandelt. Es wird testbarer Mist sein, aber es wird Mist sein.
Eine nette Sache an testbarem Mist ist, dass es refactorable Mist ist, also für einige Leute, die gut genug sind. Wir werden nur dann Lust bekommen, wenn es nötig ist. Andere hassen das und machen TDD dafür verantwortlich. Nein, das machst du.
Domain Driven Design (DDD) wird vor dem Rot-Grün-Refactor-Zyklus von TDD durchgeführt.
DDD ist das Bemühen, einen Bereich im Code zu erstellen und beizubehalten, in dem ein Domänenexperte, der die Details des Systems weitgehend nicht kennt, verstehen kann, wie das System gesteuert wird. Dies geschieht durch Abstraktion und Modellierung einer Problemdomäne auf bekannte Weise.
Ein DDD-System kann eine Architektur haben, die folgendermaßen aussieht:
Diese DDD - Architektur hat viele Namen: Clean , Onion , Hexagonal usw
Ist hier die Trennung, die ich sehe, dass viele Leute haben, wenn sie diesen Entwurf betrachten. Das ist nicht konkret. Ich kann diesem Entwurf folgen und habe noch nie etwas geschrieben, das Sie hier in einem Diagramm sehen. Ich sehe, dass andere darauf bestehen, dass es ein Use-Case-Objekt oder eine Entitätsklasse geben muss. Was dies sind, ist ein Satz von Regeln, die Ihnen sagen, mit wem Sie sprechen können und wie.
Das ist es. Befolgen Sie die Regeln dieses Entwurfs und Sie können Ihr kleines Herz heraus TDD. TDD ist es egal, mit wem Sie sprechen. Es ist wichtig, dass auf Knopfdruck nachgewiesen werden kann, dass alles, was etwas bewirkt, funktioniert oder nicht. Nicht, irgendwo ist etwas kaputt. Es sagt dir genau, was kaputt ist.
Immer noch zu vage? Schauen Sie sich das
Controler
-Use Case Interactor
-Presenter
Diagramm in der unteren rechten Ecke an. Hier sind drei konkrete Dinge, die miteinander kommunizieren. Sicher, das ist DDD, aber wie fügt man hier TDD hinzu? Verspotten Sie einfach das konkrete Zeug. Der Moderator muss Informationen erhalten. EinePresenterMock
Klasse wäre ein guter Weg, um zu überprüfen, ob sie das bekommt, was Sie erwartet haben. Hand , um dieUse Case Interactor
dasPresenterMock
und fahren die ,Use Case Interactor
als ob Sie die waren ,Controller
und Sie haben eine schöne Art und Weise zu Unit - Test derUse Case Interactor
seit der mock wird Ihnen sagen , wenn es bekommen , was Sie erwartet , es zu bekommen.Na sieh dir das an. TDD zufrieden und wir mussten mit unserem DDD-Design nicht viel anfangen. Wie ist das passiert? Wir haben mit einem gut entkoppelten Design begonnen.
Wenn Sie TDD verwenden Design zu fahren (nicht nur D evelopment) Sie ein Design erhalten, die den Aufwand reflektiert man hineinsteckt. Wenn es das ist, was du willst, gut. Aber dafür war TDD nie gedacht. Was dabei letztendlich fehlt, ist sicherlich nicht TDDs Schuld.
Bei TDD geht es nicht um Design. Wenn Sie Designänderungen vornehmen müssen, um TDD zu verwenden, haben Sie größere Probleme als das Testen.
quelle
TDD versichert, dass Ihr Code über alle notwendigen Testfälle verfügt, die parallel zur Entwicklung geschrieben wurden. Dies sollte keine Auswirkungen auf das High-Level-Design haben. Denken Sie daran, mehr in den Gräben zu arbeiten.
Bei DDD dreht sich alles um High-Level-Designs, die Sprache zwischen Domain-Experten und Ingenieuren, das Kontext-Mapping usw. Dies sollte der Treiber für das High-Level-Design der Anwendung sein.
Dies sind beide flache Erklärungen zweier leistungsfähiger Programmiermethoden. Aber am Ende des Tages erreichen sie wirklich zwei sehr unterschiedliche Dinge.
Beginnen Sie mit der DDD-Sprach- und Kontextzuordnung und beginnen Sie schließlich mit dem Üben von TDD, wenn Sie den Code schreiben. Das Üben von TDD sollte sich jedoch nicht auf das High-Level-Design auswirken, sondern sicherstellen, dass die Dinge getestet werden können. Hier gibt es eine kleine Einschränkung.
Ich denke, es könnte wichtig sein, Folgendes zu beachten: Sie sollten DDD nur üben, wenn die Anwendung komplex genug ist.
quelle
Bei DDD geht es um Software-Design.
Bei TDD geht es um Code-Design.
In DDD stellt das "Modell" die Abstraktion der Domäne dar, das gesamte Wissen des Domänenexperten.
Wir könnten TDD für das erste Code-Software-Design-Modell verwenden. Die Domäne verfügt über Geschäftsregeln und Domänenmodelle, für die der geschriebene Test (Firsts) grün sein sollte.
Tatsächlich können wir die Tests nach dem Entwerfen eines domänengetriebenen Modells codieren.
Dieses Buch "Wachsende objektorientierte Software, geführt von Tests" link-for-buy
Nehmen Sie diesen Ansatz mit einem Laufgerüst , einer hexagonalen Architektur und TDD.
Quelle: DDD schnell - InfoQ
quelle
Nein. (Domain Driven) Design sollte per Definition aus Domain-Anforderungen hervorgehen. Dies ist eine schlechte Idee, alles andere als das, was Ihr Design antreibt, zuzulassen, ob es sich um eine Testsuite, ein Datenbankschema oder ... handelt (wird fortgesetzt).
(Fortsetzung) ... oder einige kanonische Schichten von Klassen / Klassenhierarchien in Ihrer bevorzugten OO-Sprache, auch wenn es eine sehr ausgereifte und beliebte ist (schließlich können "Millionen Fliegen nicht falsch sein", oder?) .
Wenn es um DDD geht, werden die Anforderungen von OOP in einer für den Menschen lesbaren Form ausgedrückt, die für einen Nicht-Programmierer mehr oder weniger klar wäre. Streng getippte FP-Sprachen machen es besser. Ich empfehle, ein Buch über DDD mit der funktionalen Programmierung "Domain Modeling Made Functional" von Scott Wlaschin zu lesen
https://pragprog.com/book/swdddf/domain-modeling-made-functional
Sie müssen nicht die FP-Sprache verwenden, um einige der Ideen von dort auszuleihen (leider nicht alle), aber wenn Sie sie tatsächlich lesen, möchten Sie wahrscheinlich eine funktionale Sprache verwenden.
Es beantwortet auch Ihre Frage, wie TDD in ein DDD-Bild passt. Kurz gesagt, wenn Anforderungen im funktionalen Stil codiert werden, müssen nicht mehr viele Komponententests durchgeführt werden, da die meisten ungültigen Zustände und Szenarien nicht darstellbar / unmöglich zu kompilieren sind. Natürlich gibt es im FP-Projekt noch Platz für automatisierte Tests, aber die Tests werden keinesfalls zu größeren Entwurfsentscheidungen führen.
Um einen vollständigen Kreis zu bilden, kehren wir zur Titelfrage zurück, dh "Wie werden strikte TDD und DDD kombiniert?". Die Antwort ist einfach: Es gibt nichts zu kombinieren / keinen Interessenkonflikt. Entwerfen Sie nach Anforderungen, entwickeln Sie nach Design (indem Sie zuerst Tests schreiben, wenn Sie wirklich TDD machen möchten)
quelle