Domain Driven Design in Distributed Systems

9 views
Skip to first unread message

Laurin Stoll

unread,
Jun 30, 2009, 1:56:37 AM6/30/09
to altnetde
Hallo Leute,

Ich bin etwas frustiert und brauche dringend eure Hilfe, Gedanken/
Erfahrungen. Seit ich das Buch von Evans DDD lese mache ich mir immer
mehr Gedanken um DDD in Distributed Systems (DS)
Wie ihr bestimmt kennt geht man bei jedem neuen Projekt mit vollem
Ehrgeiz dran und gibt das Beste… und dann hat man einen Moment keine
Zeit sich drum zu kümmern und schon ist das Ganze nicht ganz in die
wünschenswerte Richtung gelaufen… Leider – oder nein, viel eher zum
Glück (!) – wird man immer schlauer. Aus der Erfahrung und den Fehlern
lernt man. Leider musste ich in diesem Projekt feststellen, dass da
vielleicht einige Refactors anstehen. Mein Problem: Das Domänen-Modell
ist sehr anemisch. Wieso das so kommt, glaube ich mittlerweile auch zu
wissen. Es handelt sich um eine Client/Server Anwendung und ich mache
das Domänenmodell direkt dem Client zugänglich. D.h. meine Domain
Objects haben so gut wie null Logik drin und sind quasi zu DTO’s
verkommen. Telerik Open Access (ein wirklich guter O/R Mapper)
verleitet mit dem ObjectContainer auch gerade dazu. Da kann ich
nämlich das Change Tracking bis in den Client ziehen. Leider war/ist
das keine gute Sache. Leider weiss ich auch nicht wirklich wie man das
jetzt wesentlich besser machen könnte.

Folgende Ausgangslage:

Es handelt sich um eine Client-/Server Anwendung. Der Server erhält
per WCF seine Nachrichten vom Client, bearbeitet diese und schreibt
über den OR Mapper auf die Datenbank (oder liest von der).

Nun beschreibe ich ein klassisches Szenario und wüsste gerne wie das
„richtig“ DDD in DS aussehen sollte, kann mir da jemand weiter helfen?

Der Benutzer sucht im Client nach einem Kunden mit dem Namen „Müller“.
Mein Client setzt eine Request an den Server ab mit den nötigen
Suchinformationen.

// vereinfacht
RequestBase request = new SearchRequest(„Müller“);
serviceAdapter.Enqueue(request);

Im Server empfängt ein Dispatcher meine Message (ich arbeite also nach
dem Interceptor Pattern) und verteilt diese an die jeweiligen BL
Klassen.
Der ContactManager delegiert diese Suche anschliessend an ein
Repository-layer, welches sich auf die Suche macht und eine Auflistung
von Resultaten von der Datenbank (Contact – Domänenobjekte) zurück
gibt. Dann werden diese als response zurück gesendet. (serialisiert in
ein sog. ChangeSet – ein O/R Mapper spezifische Serialisierung).
Der Client empfängt diese Antwort und zeigt die Resultate an. Danach
klickt der User auf einen Kunden und der Kunde öffnet sich in einem
Dialog wo er bearbeitet werden kann (Name / Vorname, Adresse, usw). Im
Moment wird da einfach per Databinding direkt in das Contact-Objekt
zurück geschrieben, der O/R Mapper übernimmt das ChangeTracking.
Danach sende ich wieder ein ChangeSet an den Server zurück (enthält
die Änderungen am Objekt). Diese Committet das direkt auf die
Datenbank.

So – ein klassisches Szenario. Leider bin ich mit der Zeit immer
unzufriedener mit diesem Szenario. Ich kann zu wenig Einfluss nehmen
auf das geschehen, der Server verkommt ja quasi zu nem DataAccess
Layer und mein Domänenmodell zu änemischen DTO’s. Je mehr Logik in das
System fliesst, je mehr Business Rules umso schwieriger wird die
Wartung. Ich bin im Moment zum Glück in der Lage das frühzeitig
erkannt zu haben. Wie müsste das anders aussehen? Wie realisiert ihr
ein solches, oben beschriebenes, doch recht klassisches Szenario? Was
sind eure Erfahrungen? Mir ist nicht klar, wie ich das Domain Model
nur dem Server zugänglich machen soll oder wie der Client dann mit den
Daten arbeiten soll ohne das ich für jede Operation eine Request im
Service habe. Habe übrigens mal nach DDD in DS gesucht finde aber
nicht viel dazu – nur ein Vortrag von udidahan der im August
stattfinden wird….

Für Hilfe und Inputs/Anregungen wäre ich sehr dankbar.

Viele Grüsse & besten Dank im Voraus
Laurin

Ralf Ronneburger

unread,
Jun 30, 2009, 2:23:24 AM6/30/09
to altn...@googlegroups.com
Hallo Laurin,

ich würde ganz klassisch vorgehen - für jede Operation einen Request und
das Service-Layer und alle Domain-Logic auf dem Server. Das
Service-Layer kommuniziert dann mit dem Client über DTOs, die Entities
verlassen den Server nicht.

Selbst wenn Du dann mehr Requests hast - solange das kein Problem für
die Performance darstellt, würde ich mich nicht daran stören. Du wirst
Deine Anwendung ja vermutlich nicht für eine Modem-Verbindung zwischen
Client und Server auslegen. Und falls das mal ein Problem werden sollte,
so kannst Du analog zu Deinem aktuellen Vorgehen immer noch Deine
Services so abändern, dass sie so viele Daten übertragen, dass die Daten
für die Bearbeiten-Ansicht vom Kunden in Deinem Beispiel gleich mit
übertragen werden.

Was ich Client-seitig cachen würde sind sowas wie Berechtigungen / Menüs
/ Konfigurationsdaten des Nutzers, die oft benötigt werden und sich im
Allgemeinen nicht ändern.

Viele Grüße,

Ralf



Laurin Stoll schrieb:

Markus Zywitza

unread,
Jun 30, 2009, 3:12:21 AM6/30/09
to altn...@googlegroups.com
Hallo Laurin
 
Am 30. Juni 2009 07:56 schrieb Laurin Stoll <dev...@yooapps.com>:
Service habe. Habe übrigens mal nach DDD in DS gesucht finde aber
nicht viel dazu – nur ein Vortrag von udidahan der im August
stattfinden wird….
Statt DDD in DS hat sich eher der Begriff DDDD (das erste D steht für Distributed) etabliert. Hier gibt es u. a. folgende Ressourcen:
 
-Markus

Laurin Stoll

unread,
Jun 30, 2009, 10:02:30 AM6/30/09
to altnetde
Hallo zusammen,

Erstmal vielen Dank für eure Antworten.

@ Markus: Danke da sind einige interessante Blogposts dabei, werde ich
mir anschauen. :-)

@ Ralf: ja klingt sinnig. Ich habe z.B. eine Methode AddContact
(Contact item); im server. Im client habe ich ein stupides DTO,
welches ebenfalls Contact heisst. Im server konvertiere ich dieses DTO
dann in mein Domain Object --> ebenfalls Contact nur halt nicht dumm.
Richtig?

Gut wenn das so ist, dann komme ich damit klar, so habe ich früher oft
gearbeitet. Nur diese ewige konvertiererei von DTOs in Domain Objects
und zurück geht mir ein wenig aufn Keks. Wie handhabt ihr das?

Dann aber ein nächstes Problem. Wie macht ihr das mit Listen? Bsp: Ein
Contact hält mehrere Adressen. Jetzt möchte ich im Service nicht
AddAddresse(Address item) haben, da diese ja an einem Kontakt hängen.
Ich möchte auch nicht nach jeder Adresse direkt speichern, sondern
erst, wenn der Benutzer alle hinzugefügt hat und dann speichert. Gut
könnte man sagen, die sitzen ja in einem Contact - der soll das also
auch validieren. Ok...

Trotzdem ist mir noch nicht klar, wenn ich für alles was ich mache
eine Methode mache sehe ich mehrere Nachteile:

* Ich muss ziemlich viel mit dem Server kommunizieren (ok - ob das
schlimm ist darüber kann man sich streiten)
* Ich muss alles was ich mache direkt "committen"
* Ich kann nie Massenbearbeitungsvorgänge ausführen und dann am Ende
speichern - bsp: ich möchte 10 Kontakte hinzufügen und erst dann
speichern.
* Mein Service muss mit der Zeit wohl tausende von Requests
bearbeiten!?

Wie machst du das genau? Kannst du noch ein wenig konkreter werden?

Vielen dank im Voraus und beste Grüsse
Laurin

Henning

unread,
Jul 1, 2009, 3:41:57 AM7/1/09
to altnetde
Hi, also vonwegen mappen von Domain Object -> DTO habe ich zufällig
die Tage einen Artikel von Stefan gelesen :)

http://www.lieser-online.de/blog/?p=126

Viel mir nur gerade ein, wo ich dein Post gelesen hatte ...

Stefan Lieser

unread,
Jul 1, 2009, 4:07:09 AM7/1/09
to altn...@googlegroups.com
Hi,

es gibt sogar inzwischen noch was besseres: http://www.codeplex.com/AutoMapper

Viele Grüße
Stefan

Ralf Ronneburger

unread,
Jul 1, 2009, 4:46:31 AM7/1/09
to altn...@googlegroups.com
Hallo Laurin,

kurz zu Deinen Fragen:

Laurin Stoll schrieb:


> Trotzdem ist mir noch nicht klar, wenn ich für alles was ich mache
> eine Methode mache sehe ich mehrere Nachteile:
>
> * Ich muss ziemlich viel mit dem Server kommunizieren (ok - ob das
> schlimm ist darüber kann man sich streiten)
> * Ich muss alles was ich mache direkt "committen"
> * Ich kann nie Massenbearbeitungsvorgänge ausführen und dann am Ende
> speichern - bsp: ich möchte 10 Kontakte hinzufügen und erst dann
> speichern.

Doch, in dem Fall übergibst Du einfach alle 10 Kontakte auf einmal, denn
X Kontakte auf einmal speichern ist ja in dem Fall auch eine Operation.
Insoweit stört auch das direkt committen nicht.

> * Mein Service muss mit der Zeit wohl tausende von Requests
> bearbeiten!?

Das kommt darauf an, wie fein-granular Du die Requests machst und wie
lang "mit der Zeit" ist ;-). Ich denke es werden pro Maske einige
Read-Requests und 0..1 Update-Request. Aber wenn Du die Domain-Objekte
übergibst kommst Du auch nicht mit weniger Requests aus, da Deine
Domain-Objekte vermutlich (hoffentlich) auch nicht alle miteinander
verknüpft sind. Insoweit ändert sich m.E. wenig.

Viele Grüße,

Ralf

Reply all
Reply to author
Forward
0 new messages