Fragen zur Software-Architektur

Die Frage ist doch, ob das Domänenmodell die Realität abbildet. Bis jetzt ist das hier entwickelte Modell erst statisch. Dein Programm muss aber dynamisch sein. Dazu habe ich diese Use-Story entwickelt. Würde die das beschreiben, was du willst? Da die Anwendungsentwicklung domaingetrieben sein soll, wird es während der Entwicklung schon eine Veränderung des Domänenmodells geben. Natürlich könntest du als Fachexperte sagen: Bei einer bestehenden Datenlage erwarte ich 3 Ergebnisse beim Abruf "Finde 'Waschbenzin'". Dann könntest du so einen Ampeltest entwickeln und den ausprogrammieren.
 
Was bestimmt denn die Identität von MaterialBooking? Die Referenzen auf Material und StorageLocation einzeln oder zusammen können es nicht sein, weil es mehrere Buchungen für das selbe Material im selben Lager geben kann.
Ich hätte MaterialBooking eher als ValueObject gesehen, weil es eigentlich nicht mehr darstellt, als eine Zusammenstellung von Fachwerten. Ähnlich ist es bei MaterialStock (wobei es hier die "lokale Identität" durch die MaterialId innerhalb einer StorageLocation gibt). Müssen dafür jetzt künstliche Identitäten geschaffen werden?

Nein, künstliche Identitäten braucht man nicht zwingend. Es könnte aber Hinweis darauf sein, dass das Model noch nicht fertig ist 😉

u.U. fehlt bei Buchungen noch etwas - wie kann man denn unterschiedliche aber gleiche Buchungen in der Realität unterscheiden?

QuantityUnit ist ein ValueObject und gehört zu Material. Hier gibt es u.U. ein kleines Problem, weil die QuantityUnit für das Material festgelegt wird, aber auch für die Berechnung der Bestände an anderer Stelle benötigt wird. Designfehler?
An welchen anderen Stellen wird es denn benutzt? Und wird es dort unabhängig von dem Material genutzt?


Immutable VOs können aber auch problemlos in mehreren ARs benutzt werden - es sind ja "nur" Werte 😉


Die Frage ist doch, ob das Domänenmodell die Realität abbildet. Bis jetzt ist das hier entwickelte Modell erst statisch. Dein Programm muss aber dynamisch sein. Dazu habe ich diese Use-Story entwickelt. Würde die das beschreiben, was du willst? Da die Anwendungsentwicklung domaingetrieben sein soll, wird es während der Entwicklung schon eine Veränderung des Domänenmodells geben. Natürlich könntest du als Fachexperte sagen: Bei einer bestehenden Datenlage erwarte ich 3 Ergebnisse beim Abruf "Finde 'Waschbenzin'". Dann könntest du so einen Ampeltest entwickeln und den ausprogrammieren.
Für nichts davon muss man aber über konkrete Implementierungen nachdenken 😉

Was ist ein "Ampeltest"?
 
"ample test" habe ich gelesen als Begriff für JUnit-Tests. Zuerst habe ich als Entwickler eine Erwartung, was bei einem Test zu einem roten Ergebnis führt, weil kein Code vorhanden. Dann sorge ich dafür, dass der Test erfüllt wird, also das Ergebnis grün wird. Rot und grün wie bei einer Ampel.
 
"ample test" habe ich gelesen als Begriff für JUnit-Tests. Zuerst habe ich als Entwickler eine Erwartung, was bei einem Test zu einem roten Ergebnis führt, weil kein Code vorhanden. Dann sorge ich dafür, dass der Test erfüllt wird, also das Ergebnis grün wird. Rot und grün wie bei einer Ampel.
Ahh, Test-First das meinst du, generell super, aber in diesem Fall muss halt erstmal das Modell stehen, bis man damit anfangen würde 😉
 
fehlt bei Buchungen noch etwas - wie kann man denn unterschiedliche aber gleiche Buchungen in der Realität unterscheiden?

Da es durchaus legitim ist, dass genau dieselbe Menge des selben Materials zweimal hintereinander ausgelagert wird, wäre der einzige Unterschied der Zeitpunkt.

An welchen anderen Stellen wird es denn benutzt? Und wird es dort unabhängig von dem Material genutzt?
Es wird von "Quantity" benutzt, um den Bestand zu berechnen. Hintergrund ist, dass es bei der Mengeneinheit (QuantityUnit) eine Angabe der Nachkommastellen gibt. Berechnungen wollte ich nicht mit Gleitkommazahlen durchführen, um Probleme damit zu vermeiden.

Hab leider jetzt keine Zeit mehr, bin auf Arbeit und die Pause ist um...
 
Da es durchaus legitim ist, dass genau dieselbe Menge des selben Materials zweimal hintereinander ausgelagert wird, wäre der einzige Unterschied der Zeitpunkt.
Dann würde ich den Zeitpunkt noch dazu nehmen.
Vermutlich ist dabei aber eine künstliche ID am sinnvollsten...

Es wird von "Quantity" benutzt, um den Bestand zu berechnen. Hintergrund ist, dass es bei der Mengeneinheit (QuantityUnit) eine Angabe der Nachkommastellen gibt. Berechnungen wollte ich nicht mit Gleitkommazahlen durchführen, um Probleme damit zu vermeiden.
Warum vermeidet das denn Rechnungen mit Gleitkommazahlen?
 
Rechnen mit Integer und entsprechende Interpretation der Nachkommastellen. Ist doch aber im Prinzip egal, oder? Es gibt zwei Typen "Quantity" und "QuantityUnit", die wissen wie es geht. Die Implementationsdetails sind erst mal nicht relevant.
War nur aus Interesse 😉
Da du es als Grund für die Modellierung aufführst ist es ja auch mehr als nur Implementationsdetail 😉
 
Ein kleines Statement zu meinen Fragen in https://www.java-forum.org/thema/fragen-zur-software-architektur.182299/page-9#post-1160344 wäre noch nett, wenn es eure Zeit erlaubt. 🙂
Oops, ja das bin ich noch schuldig 🙂

Gibt es eine Fausregel, wie man hier generell vorgeht?
Meinst Du bzgl. der Bildung von Aggregates? Die sind für mich Transaktionseinheiten und gewissermaßen "Wächter über Geschäftsregeln". Dazu ein Beispiel: Du hast die Regel, dass Material an einem Lagerort nur an einem Lagerplatz liegen kann. Das kann weder Material noch MaterialStock durchsetzen. Du brauchst also etwas, das den Überblick über das Lager hat - hier bietet sich StorageLocation an.

Wenn Du eine weitere Regel hast, die über mehrere StorageLocations hinweg gilt, musst Du die wieder in etwas unterbringen, das den Überblick über StorageLocations besitzt - ggf. beispielsweise in einem DomainService.

Ich hätte MaterialBooking eher als ValueObject gesehen
Das kann durchaus sein. Wenn Du Dich später nicht mehr auf eine einzelne Buchung beziehen musst (oh, Buchung 0815 war fehlerhaft), sondern MaterialBooking nur als Ereignis betrachtest, das ggf. noch nicht einmal gespeichert wird, dann handelt es sich natürlich nicht um eine Entity. Es sind auch weitere Fälle vorstellbar: z. B. könnte man MaterialBooking selbst als VO modellieren und für z. B. eine Buchungshistorie eine Entity einführen, die ihrerseits als Wert MaterialBooking bekommt.

Was besser ist? KA - das stellt sich im Verlauf noch raus; man wird beim Modell nicht zum letzten Mal den Stift angelegt haben.

Ähnlich ist es bei MaterialStock (wobei es hier die "lokale Identität" durch die MaterialId innerhalb einer StorageLocation gibt)
MaterialStock ist ganz klar eine Entity.

Nehmen wir an, Du hättest für die Lagerplätze "Bestandszettel". Wenn Du am Bestand etwas ändern willst, musst Du das im zugehörigen(!) Bestandszettel ändern. Dazu muss jeder einzelne Zettel von jedem anderen Zettel unterscheidbar sein. Bei einer Änderung brauchst Du einen ganz bestimmten Zettel und nur diesen. Bevor ich mich jetzt "verzettel", kurz: MaterialStock hat Identität -> Entity 🙂
 
Da du es als Grund für die Modellierung aufführst ist es ja auch mehr als nur Implementationsdetail
Sagen wir mal so; da ich erst mal nicht wusste, wie ich es in der Implementation lösen würde, habe ich einfach einen Datentyp daraus gemacht, um mich nicht festlegen zu müssen. Genauso wie bei der "StorageLocationId" und bei "MaterialId". Da weiß ich auch nur, dass es sie gibt, aber noch nicht wie sie aussehen wird.

Das ist doch einigermaßen korrekt?

Oops, ja das bin ich noch schuldig
Von mir gibt's keine Schuldzuweisungen 😉

könnte man MaterialBooking selbst als VO modellieren und für z. B. eine Buchungshistorie eine Entity einführen, die ihrerseits als Wert MaterialBooking bekommt.
Das erscheint mir am natürlichsten. Das MaterialBooking ist ein immutabler Wert und eine Fehlbuchung würde sowieso nur durch eine "Gegenbuchung" geändert werden können. Die Historie könnte dagegen schon wichtig sein. Lassen wir es mal so stehen. Das gefällt mir!
MaterialStock ist ganz klar eine Entity.
Da bin ich mit dir einer Meinung. Mich hat halt die fehlende Identität gestört. Ist es denn legitim, wenn die Identität nur innerhalb eines Aggregates gegeben ist (hier StorageLocation) und nicht in der gesamten Domäne?

Kurz weitergedacht hat MaterialStock natürlich eine Identität, die sich aus "MaterialId" und "StorageLocationId" zusammensetzt.
 
Das ist doch einigermaßen korrekt?
Ja, sinnvoll ist es schon, dass beides explizit zu modellieren 😉

Da bin ich mit dir einer Meinung. Mich hat halt die fehlende Identität gestört. Ist es denn legitim, wenn die Identität nur innerhalb eines Aggregates gegeben ist (hier StorageLocation) und nicht in der gesamten Domäne?

Kurz weitergedacht hat MaterialStock natürlich eine Identität, die sich aus "MaterialId" und "StorageLocationId" zusammensetzt.
Nur Aggregate-Roots müssen eine "globale" Identität haben, für alle reicht innerhalb des Aggregate-Roots eindeutig 😉

Die Zusammengesetzte ID würde bedeuten, dass ein Material nur maximal einmal an jeder Storage-Location liegen darf. War nicht auch mehrmals pro Storage-Location möglich?
 
An dieser Stelle würde ich das Domänenmodell mal abschließen. Die Vorgehensweise ist mir jetzt einigermaßen klar.

Die Aggregate, Entities und VOs sind identifiziert und müssen jetzt definiert werden.

Das ist "normale" Klassendefinition, oder? Mit öffentlichen Methoden, die die Geschäftsvorfälle abbilden?
 
Das passt schon so. Bestand wird auf Lagerortebene verwaltet nicht auf Lagerplatzebene.
Also hat MaterialStock mittlerweile keine "storageBin(Info)" mehr, die sollte dich einen Lagerplatz innerhalb des Lagerortes angeben?
Kann sein, dass ich da irgendwas auf den letzten Seiten falsch verstanden hab...

Danke für die Klärung!
Es muss dann nur sichergestellt sein, dass eine Entität nicht allein außerhalb eines Aggregates verwendet wird, sondern nur mit diesem zusammen.
"global" hat es dann "quasi" eine zusammengesetzte ID aus Aggregat-Root-ID und Entity-ID
 
Doch, die hat es weiterhin, aber sie ist nur ein Hinweis, wo das Material am Lagerort genau zu finden ist.
Hm, vielleicht sehe ich da Probleme, die gar nicht auftreten: aber angenommen das Material ist bisher an Lagerort "A" mit storageBinInfo "unten Rechts" gelagert, kann ich das gleiche Material auch weiterhin nur "unten Rechts" lagern, und nicht irgendwann noch "oben Links".

Würde dass dein ein Ändern des MaterialStocks ("unten Rechts" -> "unten Rechts und oben Links") bedeuten oder ist sowas eh nicht nötig?
 
Zuletzt bearbeitet:
Würde dass dein ein Ändern des MaterialStocks ("unten Rechts" -> "unten Rechts und oben Links") bedeuten oder ist sowas eh nicht nötig?
Das passiert definitiv und führt dazu, dass der Infotext im MaterialStock geändert werden muss. Dann liegt das Material ab diesen Zeitpunkt aber auch nicht mehr "unten rechts" sondern "oben links".
 
Das passiert definitiv und führt dazu, dass der Infotext im MaterialStock geändert werden muss. Dann liegt das Material ab diesen Zeitpunkt aber auch nicht mehr "unten rechts" sondern "oben links".
Naja, das Material kann ja weiterhin "unten rechts" liegen, nur "oben links" liegt jetzt zusätzlich etwas 😛

Aber ja, dann reicht die MaterialID als ID für MaterialStock innerhalb von StorageLocation.
 
Naja, das Material kann ja weiterhin "unten rechts" liegen, nur "oben links" liegt jetzt zusätzlich etwas
Dann hat derjenige, der es umgelagert hat, etwas falsch gemacht, denn so sollte es nicht sein. Tatsächlich machen wir gerade genau das. Wir sortieren Material neu und lagern es innerhalb eines Lagerortes, aber auch von einem Lagerort zu einem anderen Lagerort um. Ich nehme dann das Material und trage es an eine andere Stelle. Anschließend lasse ich den Lagerplatz (oder ggf. auch Lagerort) anpassen.
 
Der Domainlayer könnte dann ungefähr folgendermaßen aussehen:
domlayer.png
Wobei ein domain service Vorfälle übernimmt, die ein einzelnes Aggregat nicht allein abdecken kann. Richtig?
 
Dann hat derjenige, der es umgelagert hat, etwas falsch gemacht, denn so sollte es nicht sein. Tatsächlich machen wir gerade genau das. Wir sortieren Material neu und lagern es innerhalb eines Lagerortes, aber auch von einem Lagerort zu einem anderen Lagerort um. Ich nehme dann das Material und trage es an eine andere Stelle. Anschließend lasse ich den Lagerplatz (oder ggf. auch Lagerort) anpassen.
Ah, danke für die Aufklärung 🙂
Kenne das bisher eher Gegenteilig, weg von "alles an einem Ort" hin zu "alles einfach irgendwo hin, wo grad platz ist".


Wobei ein domain service Vorfälle übernimmt, die ein einzelnes Aggregat nicht allein abdecken kann. Richtig?
Ja, genau.
 
Damit sind wir fast wieder an den Ausgangsfragen angekommen 🙂 Was mich übrigens sehr freut!

Die UI (fxml, css, controller) interagiert mit den application services (möglicherweise (oder immer?) über UI-spezifische DTOs).

Die application services interagieren mit allen Beteiligten im domain layer (???) und mappen domain objects auf DTOs.

layers.png


aber auch von einem Lagerort zu einem anderen Lagerort

Da fällt mir doch gerade auf, dass dieser Fall von MaterialBooking nicht abgedeckt wird...🙄
 

Zurück
Oben