User Tools

Site Tools


technology:domainmodel:aggregatedesign

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

technology:domainmodel:aggregatedesign [2013/02/20 17:27]
rtavassoli
technology:domainmodel:aggregatedesign [2013/03/06 14:27] (current)
rtavassoli [Regeln]
Line 1: Line 1:
 ====== Aggregate Design ====== ====== Aggregate Design ======
 +Ein Aggregate ist eine //Konsistenzgrenze//((consistency boundary)). Das heißt, dass alle Regeln innerhalb des Aggregates immer((transaktional)) eingehalten werden können. Das heißt aber gleichzeitig, dass alle Regeln zwischen Aggregates nicht immer sofort eingehalten werden können, sondern im besten Fall //so gut es geht// und //schließlich//((Eventual consistency)).
 +\\ \\
 +Ein einfaches Beispiel ist die Auftragsnummer. Klassisch ist die Auftragsnummer Teil des Auftrags. Dieser wird in der Datenbank als eine Zeile in der Tabelle ''ORDERS'' gespeichert, und auf dem Feld ''OrderKey'' gibt es einen eindeutigen Index. Hierzu gibt es zwei Bemerkungen((Sicherlich noch viele mehr, aber zwei, die mir zu diesem Thema als relevant einfallen)).
 +>Erstens ist das ziemlich kurz gedacht. Soll man die Auftragsnummer ändern können? Wenn ja, gelten bereits verwendete Auftragsnummern dann als verbraucht? Wenn ich z.B. in einem Auftrag die Auftragsnummer von ''AG-20130306'' in ''AG-20130307'' ändere, wäre in der Datenbank kein Mechanismus enthalten, dass ein neuer Auftrag die Nummer ''AG-20130306'' erhalten darf - der Index wäre ja nicht verletzt.
 +Ein Datenbank-Index stellt eine ganz einfachere Regel sicher: //Es dürfen keine 2 oder mehrere Zeilen gleichzeitig denselben Wert haben.//
 +Der Index repräsentiert eine statische Regel die Struktur betreffend. DDD((Domain Driven Design)) ist aber ein Entwicklungsmuster, dass die Verhaltensweise der Domäne verinnerlicht. Man fragt sich nicht, ob zwei Aufträge dieselbe Nummer haben dürfen, sondern was passieren soll, wenn ein Auftrag eine Nummer erhalten soll die ein anderer bereits hat, bzw. //hatte//. Es geht darum, welche Aktionen erlaubt sind, basiert auf vorherigen Aktionen, und nicht darum, wie das System punktuell aussehen darf.
 +>Zweitens macht der Index im Grunde aus dem Auftrag eine Entität im ''Alle-Aufträge'' Aggregate. Schreiben des Indexes muss serialisiert werden um ihn einhalten zu können. Der Index ist somit ein Aggregate über alle Aufträge. Das reduziert die Partitionstoleranz des Systems, weil die Aufträge alle im selben Knoten liegen müssen.
 +===== Die Auftragsnummer =====
 +Angenommen es gibt den ''Auftrag'' und die ''Auftrags-Registratur''. Wenn der Auftrag Regeln die Auftragsnummer betreffend hat, und die Registratur Regeln die Auftragsnummer__n__ betreffend, dann sind das 2 getrennte Regelwerke, von denen lediglich eines konsistent eingehalten werden kann. Abhängig davon, welche Regeln immer und sofort eingehalten werden müssen, gehört die Auftragsnummer entweder in den Auftrag oder in die Auftrags-Registratur. Im zweiten Fall wären die Auftragsnummern //Entitäten// im Registratur //Aggregate//, und würden den Auftrag referenzieren.
 +\\ \\
 +==== Auftragsnummer redundant und synchron in mehreren Aggregates halten ====
 +Warum nicht einfach die Auftragsnummer in beiden Aggregates halten? Dann könnte man alle Regeln zur Auftragsnummer im Auftrag einhalten, sowie in der Registratur.
 +\\ \\
 +Das mag auf den ersten Blick verlockend klingen. Bei näherer Betrachtung ist es aber recht //gefährlich//. Man muss nämlich Mechanismen einbauen, die die Auftragsnummern in beiden Aggregates synchronisiert. Eine (verteilte) Transaktion wäre dafür ein möglicher Weg. Starte Transaktion, setze dieselbe Auftragsnummer im Auftrag und in der Registratur, und wenn einer der beiden die Nummer ablehnt, storniere die Transaktion. Im Jargon von DDD würde man das über einen //Domain Service// umsetzen.
 +\\ \\
 +Auch hier habe ich einige Bedenken.
 +>Erstens hat man nun zwei //Quellen der Wahrheit//(("two sources of truth")). Was ist nun die Auftragsnummer? Das, was im Auftrag steht oder das was in der Registratur steht? Das wäre zwar egal, weil dort immer dasselbe stehen sollte, aber die Gleichheit wird über Mechanismen sicher gestellt, die nicht Teil der Aggregates selbst sind. Bei großen und komplexen Systemen sind solche Mechanismen insofern gefährlich, weil sie vielleicht von einem neuen Entwickler umgangen werden, weil er die Relevanz nicht erkennt. Er erlaubt dann eine Änderung einer Auftragsnummer in der Registratur ohne eine gleichzeitige Änderung im Auftrag. Und schon haben wir den Salat, einen Fehler der nicht vorhersehbar war und nur schwer zu beheben ist.
 +==== Regeln ====
 +Man sollte also erst mal analysieren, welche Regeln es gibt, und wie sie einzuhalten sind - welche Regeln können schließlich konsistent gemacht werden? Eine pseudo-Regel ist
 +> Man möchte das parallele Arbeiten an den Aufträgen nicht serialisieren. Wenn z.B. gleichzeitig an tausenden von Aufträgen gearbeitet wird, muss es möglich sein, die Änderungen zu speichern, ohne dass es Versionskonflikte hagelt.
 +Das heißt, dass ein Aggregate über alle Aufträge nicht in Frage kommt.
 +> Zwei Aufträge dürfen niemals dieselbe Auftragsnummer erhalten. Man bedenke eine Systemintegration, in der Aufträge anhand der Auftragsnummer an ein Fremdsystem exportiert wird. Wenn ein neuer Auftrag eine bereits verwendete Auftragsnummer erhält - wenn auch nur vorübergehend - ist eine Korrektur über Systemgrenzen hinweg nur sehr schwer machbar sollte das Fremdsystem die Möglichkeit einer doppelten Auftragsnummer nicht erlauben.
 +Das heißt, dass die Auftragsnummer nicht schließlich konsistent sein darf.
 +=== Umsetzung ===
 +Es gibt nur die eine Lösung, dass es zwei Aggregates geben muss. Es gibt den ''Auftrag'' und die ''Auftrags-Registratur''. Die Auftragsnummer wird in der Registratur vergeben, und das Ergebnis ist Teil des Auftrags im Lesemodell. Die Auftragsnummernvergabe wird zwar serialisiert, das passiert i.d.R. pro Auftrag nur einmal. Alle anderen Arbeiten am Auftrag passieren isoliert im Auftrags-Aggregate.
 +== Weitere Regeln ==
 +Es gibt noch andere Regeln, die denkbar sind. Z.B. könnte eine lauten: //Ein Auftrag darf nur freigegeben werden, wenn er eine Auftragsnummer hat//. Wie kann diese Regel im Auftrag eingehalten werden, wenn die Auftragsnummer nicht Teil des Auftrags ist?
 +\\ \\
 +Das müsste über Workflows gesteuert werden. Die Auftragsfreigabe kann das Lesemodell der Registratur verwenden um zu überprüfen, ob der Auftrag eine((eindeutige)) Auftragsnummer hat. Der Workflow, der hierfür umgesetzt werden muss, ist der, dass die Registratur Auftragsnummern nicht mehr ändern darf. Dann steht einer sicheren Auftragsfreigabe nichts mehr im Wege.
 +\\ \\
 +Wenn die Umsetzung mit Domain Services unsicher war, ist das aber ebenso unsicher. Auch hier könnte ein neuer Entwickler((Junior-Entwickler)) in die Registratur eine Methode ''RemoveOrderKey'' einbauen. Es gäbe dann einen freigegebenen Auftrag ohne Auftragsnummer.
 +\\ \\
 +Nun, die Beispiele sind wahrscheinlich sehr naiv. Innerhalb einer Domäne, bzw. eines Bounded Contexts können die Aggregates nicht in Isolation von einander gebaut werden. Es setzt sich ja nicht jemand an ein Aggregate und programmiert es beliebig um. So könnten auch Regeln innerhalb des Aggregates verletzt werden, wenn ein neuer Entwickler nicht weiß, was er tut.
 +=== Einen Schritt zurück ===
 +Worum geht es bei der Auftragsnummer? Angenommen sie wird dem Auftrag zugeteilt, so wie eine Sozialversicherungsnummer. Dann kann der Auftrag damit nichts anfangen, er ist für die Nummer nicht verantwortlich! Was auch immer ihm zugeteilt wird, akzeptiert er. In dem Fall kann die Auftragsnummer teil des Lesemodell des Auftrags sein, er kann sie ja selbst nicht beeinflussen und hat keine Regeln bezüglich der ihm zugewiesenen Nummer.
 +\\ \\
 +Ja, aber was wann ich in meinem System Fremdaufträge akzeptiere? Und diese eintippe? Und mich vertippe? Das muss ich korrigieren können. Auch nachträglich, nachdem alles mögliche mit der Auftragsnummer passiert ist. Trotzdem sollte das System doppelte Auftragsnummern verhindern. Aber in diesem Fall wird die geänderte Nummer für neue Aufträge frei gegeben, denn ich habe mich vielleicht so vertippt, dass ich eine Nummer eines noch einzugebenden Auftrags eingetragen habe.
 +\\ \\
 +Die Regeln hängen also auch davon ab, wie das System verwendet werden soll! Ist es ein führendes System? Dann kann man die Auftragsnummer automatisch vergeben und sie darf nicht mehr verändert werden. Ist es nicht das führende System, dann muss die Auftragsnummer frei vergeben werden dürfen, verändert werden dürfen, usw. Soll das somit auch noch pro Kunden konfigurierbar sein? 
 +=== Prozesse, Prozesse, Prozesse ===
 +Es gibt mehrere Möglichkeiten der Umsetzung. Angenommen, der Auftrag gilt mit der ersten Lieferschein Erstellung als unveränderbar. Der Lieferschein darf ebenso nicht mehr verändert werden sobald eine Rechnung für ihn geschrieben wurde.
 +\\ \\
 +Oder man dreht das Ganze um und erlaubt einen Lieferschein nur für einen freigegebenen Auftrag, und eine Rechnung für einen freigegebenen Lieferschein, in dem Wissen, dass eine Freigabe gleichbedeutend ist mit einer Unveränderlichkeit des Auftrags, bzw. des Lieferscheins.
 +\\ \\
 +Man muss aber die Möglichkeit der Korrektur vorhalten. Das fällt dann unter Change-Management((Man-agement, also das //Altern des Mannes//. Ist das die Aufgabe eines //man-agers//, seine angestellten so zu quälen, dass sie altern?)). Man könnte also auch genauso erlauben, dass ein Auftrag jederzeit verändert werden darf, ganz egal ob ein Lieferschein bereits erstellt wurde oder nicht. In dem Fall würde u.U. ein Prozess anspringen, der den Lieferschein korrigiert, bzw. einen korrigierten Lieferschein raus schickt. Und das würde wiederum einen Prozess anstoßen, der eine Gutschrift und eine neue Rechnung an den Kunden schickt.
 +\\ \\
 +Und genau diese Prozesse sind es, welche die Domäne interessant machen. Die Objekte((Auftrag, Lieferschein, Rechnung)) sind locker mit einander verknüpft, aber vernünftige Prozesse stellen sicher, dass das System schließlich konsistent ist, d.h. dass letztendlich alles wieder zusammen passt, auch wenn nachträglich was verändert wird.
 +\\ \\
 +Ich bin aber eher ein Fan davon, es nicht ''top-down'' sondern ''bottom-up'' zu lösen. Damit der Auftrag verändert werden kann, muss vorher der Lieferschein korrigiert werden. Und damit das möglich ist, muss erst die Rechnung gut geschrieben werden. Also nicht einfach den Auftrag ändern lassen und dann nachträglich Dinge korrigieren müssen, sondern vorher die Dinge so einrichten, dass man den Auftrag sorglos ändern kann. Das ist genauso flexibel, der Anwender ist dadurch aber vorher gezwungen sich Gedanken über die Änderungen zu machen, und nicht nachträglich, wenn er den von ihm verursachten Schlamassel wieder aufräumen muss.
 +\\ \\
 +Die Schwierigkeit mit meinen Ansatz ist nur, dass die Objekte nicht mehr locker mit einander verknüpft sind, sondern sondern stark. Auftrag, Lieferschein und Rechnung gehören zusammen und haben gemeinsame Regeln. Im Dienstleistungsbereich genauso das Projekt, der Zeitdatensatz, der Wochenbericht((gibt es nicht mehr)), und die Rechnung.
 +\\ \\
 +Der ''top-down'' Ansatz ist reaktiv, und erlaubt ein offeneres Entitätsmodell. Wie immer hängt es davon ab, was gefordert ist, welchen Ansatz man letztendlich wählt.
 +\\ \\
 +Was aber schön ist, ist ein Standard den man in den meisten Fällen anwenden kann ohne sich großartig Gedanken machen zu müssen. Am besten ein Standard der die am restriktivste Möglichkeit darstellt, also für alles funktioniert. Nur wenn die Umsetzung zu restriktiv ist kann man Fallweise nach anderen Lösungen suchen. Solch ein Standard wäre z.B. das [[technology:reservationpattern|Reservation Pattern]].
 ===== Beispiel Projektstruktur ===== ===== Beispiel Projektstruktur =====
 {{ :technology:domainmodel:projectstructuresummary.png?nolink |}} {{ :technology:domainmodel:projectstructuresummary.png?nolink |}}
technology/domainmodel/aggregatedesign.1361377639.txt.gz · Last modified: 2013/02/20 17:27 by rtavassoli