# Fragen zur Software-Architektur



## temi (2. Aug 2018)

Hallo zusammen,

ich habe einige Fragen zur Softwarearchitektur bei denen ich mir trotz viel Recherche nicht sicher bin, ob ich das richtig handhaben möchte.

Es geht um eine Lagerverwaltung, d.h. es sollen Artikel die in unterschiedlichen Lagern liegen gesucht und ein-/ausgebucht werden können.


Damit es jetzt nicht zu umfangreich wird nur ein kleiner Auszug daraus und ich beginne auf der "Datenseite". Nehmen wir an es gibt die Datenbanktabellen "ItemTable" (die Artikel) und "BaseUnitTable" (die Mengeneinheit eines Artikels). Daten im ItemTable halten einen Fremdschlüssel auf die zugehörige BaseUnit. Weitere Tabellen wären z.B. StorageTable (Lager), ItemStockTable (in den Lagern gelagerte Artikel) usw.

In einem zugehörigen Domänenmodell gäbe es jetzt entsprechende Klassen (Aggregate? Entities?) "Item" und "BaseUnit", wobei ein Item ja auch eine BaseUnit hat.

Außerdem in der Datenzugriffsschicht die Repositories "ItemRepository" und "BaseUnitRepository" (wobei vom ItemRepository ebenfalls die zugehörige BaseUnit mitgeliefert wird, aber zur Stammdatenpflege von BaseUnits müssen diese auch unabhängig verfügbar sein). Viel Geschäftslogik wird es in diesen beiden Klassen nicht geben. Bei weiteren Domänenklassen, die z.B. Lagerbuchungen verwalten ist das dann spätestens der Fall.

Auf der UI-Seite haben wir sowas wie

"EditItemView.fxml" + "EditItemView.css" + "EditItemController.java"
"EditBaseUnitView.fxml" + "EditBaseUnitView.css" + "EditBaseUnitController.java"

Ist das soweit erst mal korrekt?

Die Controller benötigen ja nicht unbedingt Klassen aus dem Domänenmodell, sondern ggf. Datenobjekte mit speziell zusammengestellten Inhalten, z.B. eine Tabelle von Artikeln mit ihren Beständen in den unterschiedlichen Lagern.

Ist das so richtig, dass die UI-Schicht ihre eigenen Datenklassen für ihre Belange definiert?

Woher erhält die UI-Schicht diese Daten? Gibt es dafür noch eine zusätzliche Schicht zwischen UI und Domäne und wie wird diese im Normalfall realisiert? Oder greift die UI direkt auf Domänenobjekte zu?

Ich hoffe es findet sich jemand, der meine Fragen beantworten kann und bedanke mich schon mal dafür

Gruß,
Temi


----------



## temi (2. Aug 2018)

Ich habe mal eine kleine Skizze dazu angefertigt und noch einen zusätzlichen Layer "Services" eingefügt. Demnach könnte die UI über einen (mehrere) Service z.B. "getItemListWithStorageAndStock" oder "insertNewItem" auf die darunter liegenden Daten zugreifen, die gesuchten Daten aus den Repositories anfordern und ggf. auf UI-DTOs mappen. Korrekt so?


----------



## mrBrown (2. Aug 2018)

Im wesentlichen klingt das passend.

Service kann man aber in dem Fall in zwei Service-Layer teilen: einmal Services im Domain-Layer, die dann auch Domänen-Logik enthalten, und einmal Application-Layer, welches die Logik der Applikation und auch das Mapping von Domäne<->DTO enthält, aber eben keine Domänen-Logik.



temi hat gesagt.:


> In einem zugehörigen Domänenmodell gäbe es jetzt
> entsprechende Klassen (Aggregate? Entities?) "Item" und "BaseUnit", wobei ein Item ja auch eine BaseUnit hat.


Aus der knappen Beschreibung schwierig abzuleiten, aber spontan wäre Item ein Aggregate (und damit auch Entity), und BaseUnit könnte ein Value-Object sein (wenn es denn eine "Einheit" darstellt) oder eben auch eine Entität oder sogar Aggregate - hängt von der Verwendung ab 



temi hat gesagt.:


> Außerdem in der Datenzugriffsschicht die Repositories "ItemRepository" und "BaseUnitRepository" (wobei vom ItemRepository ebenfalls die zugehörige BaseUnit mitgeliefert wird, aber zur Stammdatenpflege von BaseUnits müssen diese auch unabhängig verfügbar sein). Viel Geschäftslogik wird es in diesen beiden Klassen nicht geben. Bei weiteren Domänenklassen, die z.B. Lagerbuchungen verwalten ist das dann spätestens der Fall.


Repositorys sollten generell keine Geschäftslogik enthalten, die gehört in Domänenobjekte und Services, sondern nur Speichern, Laden und Suchen


----------



## temi (2. Aug 2018)

mrBrown hat gesagt.:


> Aus der knappen Beschreibung schwierig abzuleiten, aber spontan wäre Item ein Aggregate (und damit auch Entity), und BaseUnit könnte ein Value-Object sein (wenn es denn eine "Einheit" darstellt) oder eben auch eine Entität oder sogar Aggregate - hängt von der Verwendung ab



Die beiden Datenbanktabellen würden ungefähr so aussehen:

```
//ItemTable
UID id
String shortName
String description
UID fkBaseUnit

//BaseUnit
UID id
String shortName // z.B. "ST"
String description // z.B. "Stück"
int decimals // Anzahl der Nachkommstellen, im Beispiel "0"
```
BaseUnit legt sozusagen fest, wie Ein-/Ausbuchungen verrechnet, bzw. angezeigt werden (z.B. damit man nicht nur ganze Meter ausbuchen kann), ist aber im Prinzip immutabel.

Da wäre auch gleich eine Frage, BaseUnit hat ja allein für die DB eine Identität (die id). Macht es das allein schon zum Entity? Dürfte ja eigentlich nicht so sein, weil sonst ja grundsätzlich alles was in der DB gespeichert wird ein Entity wäre.[/code]


----------



## temi (2. Aug 2018)

mrBrown hat gesagt.:


> Repositorys sollten generell keine Geschäftslogik enthalten, die gehört in Domänenobjekte und Services, sondern nur Speichern, Laden und Suchen


Ja, war von mir falsch formuliert, bzw. im falschen Zusammenhang. Aber dafür gleich noch eine Frage: Wo "leben" denn die Domänenobjekte? Im Repository?

Ich hoffe man versteht die Frage: Die Domänenobjekte sind ja nicht einfach so da. In der Software sind sie ja auch in einer Collection gespeichert, die irgendwo enthalten ist.


----------



## temi (2. Aug 2018)

mrBrown hat gesagt.:


> Service kann man aber in dem Fall in zwei Service-Layer teilen: einmal Services im Domain-Layer, die dann auch Domänen-Logik enthalten, und einmal Application-Layer, welches die Logik der Applikation und auch das Mapping von Domäne<->DTO enthält, aber eben keine Domänen-Logik.


Könnte man dann sagen:
Der Domain-Layer enthält Domänenobjekte, Domain-Services und Repositories.
Der Application-Layer enthält DTOs, UI-Controller und UI-Services. 
Der Application-Layer ist demnach zusammen mit den deklarativen Teilen (fxml, css) die eigentlich ausgeführte Applikation (und womöglich im Gesamtprojekt ein separates Unterprojekt)?

Würde man die speziell für die UI bestimmten Datenobjekte korrekt als DTO bezeichnen, oder anders?


----------



## mrBrown (2. Aug 2018)

temi hat gesagt.:


> BaseUnit legt sozusagen fest, wie Ein-/Ausbuchungen verrechnet, bzw. angezeigt werden (z.B. damit man nicht nur ganze Meter ausbuchen kann).
> 
> Da wäre auch gleich eine Frage, BaseUnit hat ja allein für die DB eine Identität (die id). Macht es das allein schon zum Entity? Dürfte ja eigentlich nicht so sein, weil sonst ja grundsätzlich alles was in der DB gespeichert wird ein Entity wäre.


So in etwa ist es. Ergibt sich die Identität aus der ID -> Entity. (Werte können sich ändern, es ist aber das gleiche)
Ergibt sich die Identität aus den Werten -> Value-Object. (Wenn die Werte sich ändern, ist es was anderes)

Bei der Verwendung von DBs vermischt sich das leider schnell schnell. Leichter macht man das, wenn man dabei alle Spalten immutable macht.

BaseUnit dürfte ein Value-Object sein: Wenn man irgendwas ändert, ist es ja eine andere Unit.




temi hat gesagt.:


> Ja, war von mir falsch formuliert, bzw. im falschen Zusammenhang. Aber dafür gleich noch eine Frage: Wo "leben" denn die Domänenobjekte? Im Repository?


Jein, es ist eher ein Wann als ein Wo.
Stell dir ein Repo als eine Collection vor, du kannst Werte reinlegen und rausnehmen, wie bei einer Liste.
Das lebt, bevor es drin ist, das lebt, solange es drin ist, das lebt wenn du es wieder rausnimmst, das lebt, bis du es irgendwann explizit "tötest".



temi hat gesagt.:


> Könnte man dann sagen:
> Der Domain-Layer enthält Domänenobjekte, Domain-Services und Repositories.
> Der Application-Layer enthält DTOs, UI-Controller und UI-Services.
> 
> Würde man die speziell für die UI bestimmten Datenobjekte korrekt als DTO bezeichnen, oder anders?


Das dürfte alles so passen


----------



## temi (2. Aug 2018)

mrBrown hat gesagt.:


> BaseUnit dürfte ein Value-Object sein: Wenn man irgendwas ändert, ist es ja eine andere Unit.


Das klingt sinnvoll. Ich würde noch ein Feld Status (gültig, nicht gültig, o.ä.) vorsehen, da eine einmal festgelegte BaseUnit, die von einem Item verwendet wird, nicht mehr geändert werden darf.


----------



## mrBrown (2. Aug 2018)

temi hat gesagt.:


> Das klingt sinnvoll. Ich würde noch ein Feld Status (gültig, nicht gültig, o.ä.) vorsehen, da eine einmal festgelegte BaseUnit, die von einem Item verwendet wird, nicht mehr geändert werden darf.


Wie können denn ungültige Units entstehen?


----------



## temi (2. Aug 2018)

mrBrown hat gesagt.:


> Jein, es ist eher ein Wann als ein Wo.
> Stell dir ein Repo als eine Collection vor, du kannst Werte reinlegen und rausnehmen, wie bei einer Liste.
> Das lebt, bevor es drin ist, das lebt, solange es drin ist, das lebt wenn du es wieder rausnimmst, das lebt, bis du es irgendwann explizit "tötest".


In meinen Worten: Der Benutzer fordert z.B. eine Liste von Items aus dem Repository an. Die Items werden aus der DB gelesen, im Repository (erzeugt und) gespeichert und dem Application-Layer zum Mapping, Anzeigen usw. weiter gegeben.

So ich merke gerade, jetzt wird es komplizierter, weil das Domänenmodell noch zu rudimentär ist:



mrBrown hat gesagt.:


> Repositorys sollten generell keine Geschäftslogik enthalten, die gehört in Domänenobjekte und Services, sondern nur Speichern, Laden und Suchen



Der Benutzer nimmt eine Buchung für ein Item vor. Wie geht es jetzt weiter?

Ich versuche es mal selbst:
Der entsprechende Service holt sich die notwendigen Daten aus einem oder mehreren Repositories. Der Service ruft die entsprechenden Methoden auf den Domänenobjekten auf, um die Buchung vorzunehmen und speichert sie in die Repos zurück.
Es gälte jetzt noch eine Strategie festzulegen, wann die Daten wieder aus den Repos entfernt werden. Sofort wenn die Transaktion beendet wurde oder z.B. nach einer gewissen Zeit der Nichtbenutzung.


----------



## temi (2. Aug 2018)

mrBrown hat gesagt.:


> Wie können denn ungültige Units entstehen?


Ungültig ist das falsche Wort, etwas besseres fällt mir gerade nicht ein. Es geht darum dass für ein erzeugtes Item mit einer bestimmten BaseUnit immer diese BaseUnit verwendet werden muss, um die Konsistenz sicher zu stellen.
Es ist aber vorstellbar, dass eine neue BaseUnit "Meter" erstellt wird, die nun eine anstatt zwei Nachkommastellen verwendet. Für neue Items ist diese dann die "gültige" BaseUnit. Der ursprüngliche zweistellige "Meter" steht für neue Items dann nicht mehr zur Verfügung.


----------



## mrBrown (2. Aug 2018)

temi hat gesagt.:


> In meinen Worten: Der Benutzer fordert z.B. eine Liste von Items aus dem Repository an. Die Items werden aus der DB gelesen, im Repository (erzeugt und) gespeichert und dem Application-Layer zum Mapping, Anzeigen usw. weiter gegeben.


Auf reiner Code Ebene: ja, das Repo lädt bestehende Entitäten aus der DB und gibt sie weiter.



temi hat gesagt.:


> Der Benutzer nimmt eine Buchung für ein Item vor. Wie geht es jetzt weiter?
> 
> Ich versuche es mal selbst:
> Der entsprechende Service holt sich die notwendigen Daten aus einem oder mehreren Repositories. Der Service ruft die entsprechenden Methoden auf den Domänenobjekten auf, um die Buchung vorzunehmen und speichert sie in die Repos zurück.


Kommt drauf an, was eine "Buchung" ist 

Aber ja, generell: die Applikation bekommt die Daten von einem Repo, ruft entsprechende Methode auf, und gibt sie in an das Repo zurück.



temi hat gesagt.:


> Es gälte jetzt noch eine Strategie festzulegen, wann die Daten wieder aus den Repos entfernt werden. Sofort wenn die Transaktion beendet wurde oder z.B. nach einer gewissen Zeit der Nichtbenutzung.


Das wäre Domänen-Logik, das Repo hat da nichts mit zu tun 

Müssen Daten überhaupt gelöscht werden? Was wäre denn in Domänensprache ein löschen? Gibt es dort überhaupt ein "löschen"? 



temi hat gesagt.:


> Ungültig ist das falsche Wort, etwas besseres fällt mir gerade nicht ein. Es geht darum dass für ein erzeugtes Item mit einer bestimmten BaseUnit immer diese BaseUnit verwendet werden muss, um die Konsistenz sicher zu stellen.
> Es ist aber vorstellbar, dass eine neue BaseUnit "Meter" erstellt wird, die nun eine anstatt zwei Nachkommastellen verwendet. Für neue Items ist diese dann die "gültige" BaseUnit. Der ursprüngliche zweistellige "Meter" steht für neue Items dann nicht mehr zur Verfügung.


Also gibt es unterschiedliche "Typen" von BaseUnits (Meter wäre so ein Typ), und zu einem Zeitpunkt gibt es jeweils eine aktuelle Definition des Types?


----------



## temi (3. Aug 2018)

mrBrown hat gesagt.:


> Also gibt es unterschiedliche "Typen" von BaseUnits (Meter wäre so ein Typ), und zu einem Zeitpunkt gibt es jeweils eine aktuelle Definition des Types?


Genau, im Regelfall gibt es eine Anzahl von BaseUnits, die nicht mehr verändert werden: ST (Stück, 0 Nachkommastellen), PK (Pack, 0 NK), M (Meter, 2 NK), usw. Falls eine dieser Einheiten verändert wird, würde ich die "alte" Einheit als "deprecated" markieren und für neue Items nicht mehr verwendbar.
Wenn ich noch einmal darüber nachdenke, dürfte die Auswahl an unterschiedlichen Basismengeneinheiten doch arg begrenzt sein, so dass es möglicherweise sinnvoll ist diese gar nicht in der DB vor zu halten, sondern fest zu hinterlegen als eine Art Set von BaseUnits.


----------



## temi (3. Aug 2018)

mrBrown hat gesagt.:


> Kommt drauf an, was eine "Buchung" ist



Eine Buchung ist das Hinzufügen oder das Entnehmen von Artikeln in oder aus einem Lagerort. Artikel können an unterschiedlichen Orten  oder möglicherweise mehrfach gelagert sein. Das ist in der DB durch eine Tabelle mit Fremdschlüsselbeziehungen realisiert:
fkItem, fkStorage, Amount. Im einfachsten Fall wird für eine Buchung also nur die Menge erhöht oder verringert (sofern > 0). Im gleichen Zug wird eine Prüfung durchgeführt, ob ein definierter Mindestbestand unterschritten wurde und ggf. ein Eintrag in eine entsprechende Tabelle vorgenommen. Daraus können dann sofort oder später Bestellungen generiert werden.

Was könnte also genau ablaufen:

Der User sucht nach einem bestimmten Artikel, z.B. über einen Suchbegriff
=> Aufruf Applikations-Service mit Suchbegriff
=> Aufruf Domänen-Service mit Suchbegriff
=> Aufruf Repo mit Suchbegriff
=> Rückgabe der Daten über Dom-Service an App-Service an UI-Controller​Der User nimmt eine Buchung (in diesem Fall eine Entnahme) vor:
=> Aufruf App-Service mit Item-Id, Lagerort-Id und Menge
=> Aufruf Dom-Service mit Item-Id, Lagerort-Id und Menge
=> Aufruf ItemStock-Repo und Prüfen des Bestands
=> Aufruf ItemStock-Repo und Ändern des Bestands
=> Ggf. Aufruf AlertRepo und Hinzufügen eines Alerts (Menge unterschritten)​
In diesem Szenario leitet der Applikations-Service Anfragen einfach an den Domänen-Service weiter. Bei der Rückgabe von Daten nimmt er zusätzlich noch ein Mapping auf UI-DTOs vor.

Wenn ich mir das so durchlese, dann steckt jetzt die gesamte Logik in den Services und die Domänenobjekte haben eigentlich gar nichts zu tun. Das kommt mir falsch vor.


----------



## mrBrown (3. Aug 2018)

Die Typen in der Datenbank zu halten hat durchaus auch Vorteile, zB kann man neue hinzugefügt ohne alles neu bauen zu müssen.
Das „deprecated“ kann man zB übers Datum lösen.




temi hat gesagt.:


> Wenn ich mir das so durchlese, dann steckt jetzt die gesamte Logik in den Services und die Domänenobjekte haben eigentlich gar nichts zu tun. Das kommt mir falsch vor.


Naja, ich les da überhaupt keine Geschäftslogik raus, von daher nicht verwunderlich 

Das Menge erhöhen ist da mMn zu knapp erklärt, als dass man da ableiten könnte, wo und wie viel Logik da drin steckt.

Schon ein Domänen-Modell erstellt?


----------



## mihe7 (3. Aug 2018)

temi hat gesagt.:


> die Domänenobjekte haben eigentlich gar nichts zu tun. Das kommt mir falsch vor.





mrBrown hat gesagt.:


> Schon ein Domänen-Modell erstellt?



In dem Zusammenhang: 



temi hat gesagt.:


> d.h. es sollen Artikel die in unterschiedlichen Lagern liegen



Wo ist denn z. B. das Lager modelliert?


----------



## temi (3. Aug 2018)

mrBrown hat gesagt.:


> Die Typen in der Datenbank zu halten hat durchaus auch Vorteile, zB kann man neue hinzugefügt ohne alles neu bauen zu müssen.


Das war die ursprüngliche Grundidee.


mrBrown hat gesagt.:


> Das „deprecated“ kann man zB übers Datum lösen.


Timestamp ist eine gute Idee. Die wird es sowieso geben.


mrBrown hat gesagt.:


> Naja, ich les da überhaupt keine Geschäftslogik raus, von daher nicht verwunderlich. Das Menge erhöhen ist da mMn zu knapp erklärt, als dass man da ableiten könnte, wo und wie viel Logik da drin steckt.


Naja, sehr viel steckt auch nicht dahinter. Ich fang halt mal klein an. Für den Einstieg ist das für mich schon einigermaßen "anspruchsvoll". Mehr als prüfen, ob die Menge die entnommen werden soll auch im Lager liegt, fällt mir erst mal nicht ein.


mrBrown hat gesagt.:


> Schon ein Domänen-Modell erstellt?


Ich habe da noch recht wenig Ahnung davon (also nur, was ich bereits darüber gelesen habe), aber ich kann es mal versuchen und zur Diskussion stellen.


mihe7 hat gesagt.:


> Wo ist denn z. B. das Lager modelliert?


Ich hab für die Einstiegsfrage einiges weggelassen, aber die Lager an sich sind eine recht simple DB-Tabelle:

```
//StorageTable
UID id
String shortName // z.B. "02004"
String description // z.B. "Gebäude 2, EG, Raum 4"
```
Das gelagerte Material in einer weiteren Tabelle:

```
//ItemStockTable
UID id
UID fkItem
UID fkStorage
int amount
int limit // Mindestbestand
```
Frage am Rande: Der shortName der Lagerorte stellt eigentlich bereits eine Identität dar, da er eindeutig ist. Ich würde für die Datenbanktabellen trotzdem gerne einen zusätzlichen eindeutigen Schlüssel verwenden, in diesem Fall die UID, wobei die auch eine von der DB erzeugte fortlaufende Nummer sein könnte. Ist daran etwas auszusetzen?


----------



## mrBrown (3. Aug 2018)

temi hat gesagt.:


> die Lager an sich sind eine recht simple DB-Tabelle





temi hat gesagt.:


> Das gelagerte Material in einer weiteren Tabelle





temi hat gesagt.:


> Frage am Rande: Der shortName der Lagerorte stellt eigentlich bereits eine Identität dar, da er eindeutig ist. Ich würde für die Datenbanktabellen trotzdem gerne einen zusätzlichen eindeutigen Schlüssel verwenden, in diesem Fall die UID, wobei die auch eine von der DB erzeugte fortlaufende Nummer sein könnte. Ist daran etwas auszusetzen?



Das ist alles kein Domänen-Modell, sondern Datenbank-Details 

Domänen-Modell wäre eher sowas wie "Es gibt Lager, Lager haben einen Ort und eine Beschreibung. In einem Lager ist eine bestimmte Menge an Materialien gelagert. Pro Lager gibt es dabei einen Mindestbestand eines Materials."

Das ganze halt im Idealfall noch grafisch dargestellt


----------



## temi (3. Aug 2018)

mrBrown hat gesagt.:


> Domänen-Modell wäre eher sowas wie


Dann würde ich mal mit der textuellen Fassung anfangen. Ich melde mich wieder.


----------



## mrBrown (3. Aug 2018)

Sinnvoll ist meist eine grafische Darstellung


----------



## temi (3. Aug 2018)

Ungefähr so?


----------



## mrBrown (3. Aug 2018)

Ja, wobei beschriftete Beziehungen da super wären 

Und natürlich schadet ein Blick auf die entsprechende Syntax nicht: https://de.wikipedia.org/wiki/Klassendiagramm  (nicht wundern, Domänenmodell sind zwar keine Klassendiagramme, aber werden mit den gleichen Elementen modelliert)


----------



## temi (3. Aug 2018)

mrBrown hat gesagt.:


> Ja, wobei beschriftete Beziehungen da super wären


Ein Beispiel wäre nett.
Gibt es dafür eine empfehlenswerte und leicht bedienbare Software, die unter Linux läuft? Mit LibreOffice ist das etwas beschwerlich.


----------



## mrBrown (3. Aug 2018)

temi hat gesagt.:


> Ein Beispiel wäre nett.


zB was BaseUnit mit Material zu tun hat. In dem Fall könnte es ein "wird gehandelt in Einheit"



temi hat gesagt.:


> Gibt es dafür eine empfehlenswerte und leicht bedienbare Software, die unter Linux läuft? Mit LibreOffice ist das etwas beschwerlich.


Lucidchart (wobei man das nur wirklich Sinn hat, wenn man als Student die Pro-Version gratis bekommt) oder Draw.io, sind beide Web-basiert


----------



## mihe7 (4. Aug 2018)

temi hat gesagt.:


> Gibt es dafür eine empfehlenswerte und leicht bedienbare Software


Für schnelle, einfache Sachen nehme ich UMLet.


temi hat gesagt.:


> Ich hab für die Einstiegsfrage einiges weggelassen, aber die Lager an sich sind eine recht simple DB-Tabelle:


Das Lager kam in der Einstiegsfrage vor, wurde dann aber nicht weiter berücksichtigt. Hintergrund für das Lager war Deine Frage nach der Geschäftslogik. Die Frage wäre, ob das Lager nicht für einen Teil der Logik zuständig ist. Unabhängig davon bist Du zu sehr auf die DB fokussiert. Die interessiert erst einmal überhaupt nicht.


----------



## temi (4. Aug 2018)

draw.io funktioniert gut für mich. Hier ein neuer Versuch:





mihe7 hat gesagt.:


> Unabhängig davon bist Du zu sehr auf die DB fokussiert. Die interessiert erst einmal überhaupt nicht.


Damit hast du wohl recht.

Übrigens: Ein herzliches Dankeschön an euch beiden, dass ihr euch die Zeit nehmt meine Fragen zu beantworten. Für einen Autodidakten, der das nur aus Freude am Programmieren macht, ist es nicht so leicht, wenn man keinen Ansprechpartner hat.

Wenn ich mein Werk so betrachte, dann ist es schon eher ein Klassendiagramm. Ist das so richtig? "MaterialStock" könnte anstatt der Aggregation mit "StorageLocation" auch einfach ein Feld besitzen "storageLocation: StorageLocation".


----------



## horstiii1 (4. Aug 2018)

mihe7 hat gesagt.:


> Für schnelle, einfache Sachen nehme ich UMLet.


Oder: http://nclass.sourceforge.net/ damit lassen sich auch schnell schöne Ergebnisse erzielen finde ich. 
Normale Klassendiagramme nach UML(2.0) oder?


----------



## temi (4. Aug 2018)

So, ich habe noch mal etwas weiter gemacht. Hier würde ich erst mal stoppen und eure Kommentare abwarten.

 

Was noch fehlt: Bestellungen, Lageretiketten, ???


----------



## temi (4. Aug 2018)

Ich habe jetzt noch einen etwas erweiterten Ansatz versucht und dabei berücksichtigt, was ich vom Material erwarte, dass es tun kann:

 

Wie verfährt man im DomainModel mit Hilfsklassen wie* State, StateType* oder *Quantity*? So wie ich es jetzt gemacht habe, indem ich sie einfach als Typ angebe oder als separate Klasse mit Assoziation (wie bei *State* im Beitrag darüber)?

Ist das jetzt "too much" für das Material?

Alternativ könnten z.B. die Lagerplätze erst aus einem Repository geladen werden, wenn sie angefordert werden. Würde das Material dann das entsprechende Repository kennen und das selbst erledigen?

Bin ich schon wieder zu schnell, bzw. zu tief in der Implementierung?


----------



## mrBrown (4. Aug 2018)

temi hat gesagt.:


> Wenn ich mein Werk so betrachte, dann ist es schon eher ein Klassendiagramm. Ist das so richtig? "MaterialStock" könnte anstatt der Aggregation mit "StorageLocation" auch einfach ein Feld besitzen "storageLocation: StorageLocation".


Ja, Domänenmodelle sind rein technisch Klassendiagramm, allerdings nur mir konzeptionellen Klassen und ohne Methoden 
Als Feld würde man es nur modellieren, wenn es ein primitiver Typ ist, alle anderen als Assoziationen 



temi hat gesagt.:


> Wie verfährt man im DomainModel mit Hilfsklassen wie* State, StateType* oder *Quantity*? So wie ich es jetzt gemacht habe, indem ich sie einfach als Typ angebe oder als separate Klasse mit Assoziation (wie bei *State* im Beitrag darüber)?


Als eigene Klassen


----------



## temi (4. Aug 2018)

mrBrown hat gesagt.:


> und ohne Methoden


Ok, dann nehm ich die wieder raus.


mrBrown hat gesagt.:


> Als Feld würde man es nur modellieren, wenn es ein primitiver Typ ist, alle anderen als Assoziationen


Das wird aber evtl. recht unübersichtlich.

 

Ich möchte für alle Klassen einen State realisieren, d.h. ich müsste jetzt von State ausgehen Assoziationen zu allen Klassen einzeichnen. Was mache ich, z.B. mit Quantity in MaterialStock? Das wird dort für zwei Felder verwendet.

Ist das jetzt ein brauchbares DomainModel, oder fehlt etwas wichtiges?


----------



## mihe7 (4. Aug 2018)

Die Angabe der Multiplizitäten sind auf der falschen Seite. 


temi hat gesagt.:


> Das wird aber evtl. recht unübersichtlich.


Ich denke, @mrBrown meinte mit "primitive Typen" etwas anderes als int usw. Es geht mehr darum, ob es sich um ein Attribut einer Klasse (bzw. deren Objekten) handelt, oder um Beziehungen. Das Alter einer Person kann man als Attribut der Klasse Person darstellen, egal ob man "int" oder eine "Age"-Klasse verwendet. 

Gibt es dagegen eine Beziehung zu einer anderen Klasse, sagen wir mal Adresse, dann stellt man so etwas gerade in der Analyse nicht mehr als Feld dar. Erstens gehen die Multiplizitäten ggf. verloren, zweitens kann man die Beziehung dann nicht vernünftig beschreiben und drittens ist die Frage, ob im Entwurf die Beziehung tatsächlich noch so umgesetzt wird.

So sehe ich die Sache zumindest


----------



## mihe7 (4. Aug 2018)

temi hat gesagt.:


> Was mache ich, z.B. mit Quantity in MaterialStock? Das wird dort für zwei Felder verwendet.


Dann spielt eine Quantity in MaterialStock zwei verschiedene Rollen (amount, limit) und die gibt man bei der Assozitation auf Seite der Quantity an.

Nachtrag: s. z. B. https://stackoverflow.com/questions/16732607/role-name-in-association-relationship


----------



## AndiE (4. Aug 2018)

Ich würde an dieser Stelle mal eingreifen. Wie der TE ist es auch mir nicht so sehr gelungen, Vorlagen zur DDD zu finden. Ich habe mir deshalb das Kompakt-Buch von Vernon besorgt. 

Ich würde mal den Blick auf die Fach-Seite werfen. 

Momentan scheint es darauf hinauszulaufen, dass das Programm die Lagerverwaltung komplett abdecken soll. Ich würde mir dem oben angegebenen Buch vorschlagen, dass hier eine Use-Story erstellt wurde, am besten angelehnt an eine reale Einrichtung. 

Beispielsweise kann ich mir eine Firma mit zwei Filialen vorstellen. An das Hauptwerk gelieferte Materialien werden intern an die Filialen versandt oder in Lager am Hauptwerk eingelagert. Wenn es eine Getränkefirma ist, ist die Anzahl der Materialien und deren Abpackung schon recht eingeschränkt. In der Regel werden aus einem Lager auch Teile entnommen, so dass immer ein Bestand vorhanden ist. 

Ich würde das Modell dahingehend noch mal überprüfen.


----------



## temi (4. Aug 2018)

AndiE hat gesagt.:


> Ich habe mir deshalb das Kompakt-Buch von Vernon besorgt.


Das Buch hab ich auch - ist schon ziemlich kompakt. Irgendwie fehlt mir da noch was (vielleicht bin ich aber auch zu doof)


AndiE hat gesagt.:


> am besten angelehnt an eine reale Einrichtung.


Ich habe schon einen realen Hintergrund. Allerdings geht es eher um Ersatz- und Verbrauchsmaterial, das wir nicht über SAP verwalten können (dürfen). Aktuell machen wir das manuell: Fach ist leer => Katalog aufschlagen => Material bestellen. Das Problem ist häufig, dass wir Material nicht mehr finden (wir haben ein Lager im Wert von mehreren 100 T€), mit mehreren Lagerorten (z.B. Werkstatt, Keller, Dach) und vielen vielen Fächern (z.B. 001/003 => Schrank 1, Fach 3). Außerdem ist es nicht sehr praktisch, wenn man jedes mal wieder die Bestelldaten raus suchen muss und zu guter Letzt ist SAP zu doof ein Lageretikett zu drucken.

Eine User-Story ist also grob:

Material im System suchen (Volltext, Hersteller, Hersteller-Artikelnummer)
Lagerort und -platz anzeigen
Material entnehmen
Entnommene Menge aus dem Bestand ausbuchen
Sollte der Mindestbestand unterschritten werden, wird eine Bestellanforderung für diesen Artikel generiert. Die Bestellanforderung kann entweder sofort zu einer Bestellung führen oder es wird später eine "Sammelbestellung" aus aufgelaufenen Anforderungen gemacht. Die Bestellung selbst läuft über ein anderes System.

Weitere Anforderungen sind noch: Geliefertes Material in den Bestand einbuchen, Etikett für einen bestimmten Artikel oder mehrere Etiketten (z.B. Nummernbereich (Lagerort-/platzbezogen). Dazu muss zusätzlich das SAP-geführte Material aus einer CSV in dieses System importiert werden => Nummer, Kurztext, Langtext, Hersteller (nur Name), Hersteller-Artikelnummer, Lagerort, Lagerplatz, Mengeneinheit.

Vorschläge sind mir willkommen, das ist der aktuelle Stand:


----------



## temi (4. Aug 2018)

AndiE hat gesagt.:


> Wie der TE ist es auch mir nicht so sehr gelungen, Vorlagen zur DDD zu finden.


Es wäre halt klasse, DDD einmal an einem praktischen Beispiel durchzuspielen. Als "Alleinunterhalter" besteht allerdings leider das Problem, dass es kein Feedback gibt, ob man es gut macht oder alles Mist ist.


----------



## AndiE (4. Aug 2018)

So ist das noch nicht ideal. Vielleicht sagen dir "Lagerfachkarten" was. Im Prinzip heißt das, dass jede Entnahme zeitnah nachgewiesen wird. Diese wird dann anschließend verbucht. Sind Inhalte unter den Limit gesunken, werden dann neue zur Bestellung ausgeschrieben.

Daraus ergeben sich für mich diese Use-Cases:
1. Aufteilung: Zuerst kann man festlegen, welche Fächer es wo gibt. 
2. Inventur:  Nun legt man fest, wo was liegt und in welchem Umfang.
3. Zugang: Eine Lieferung von einem Lieferanten kommt. Diese wird auf die Fächer aufgeteilt
4. Entnahme: jemand schreibt eine Anforderung.  Aus den entsprechenden Fächern werden die angeforderten Mengen entnommen
5. Bestand überprüfen: Der Lagerverwalter überprüft den Bestand. Ist der Bestand einer Sache unter Soll gesunken, neu  bestellen. 

Das würde aber einen Lagerverwalter erfordern, an den Anforderungen (Materialentnahmescheine) gestellt werden, der die Lieferungen dann entsprechend zusammenstellt.


----------



## Meniskusschaden (4. Aug 2018)

temi hat gesagt.:


> und zu guter Letzt ist SAP zu doof ein Lageretikett zu drucken.


Da wird wohl nicht SAP die Partei sein, die zu doof ist, ein Etikett zu drucken.


temi hat gesagt.:


> das wir nicht über SAP verwalten können (dürfen).





temi hat gesagt.:


> Vorschläge sind mir willkommen


Falls es wirklich einen guten Grund dafür geben sollte, dass die Standard-SAP-Prozesse nicht in Betracht kommen (Schwierigkeiten beim Etikettendruck würde ich nicht dazu zählen), bleibt trotzdem noch die Option, auf Basis der SAP-Entwicklungstools eine eigene Lösung zu entwickeln. Die wäre dann vernünftig im SAP-GUI integriert und den Datenaustausch per csv-könnte man sich auch sparen.


----------



## temi (5. Aug 2018)

Meniskusschaden hat gesagt.:


> Falls es wirklich einen guten Grund dafür geben sollte, dass die Standard-SAP-Prozesse nicht in Betracht kommen (Schwierigkeiten beim Etikettendruck würde ich nicht dazu zählen), bleibt trotzdem noch die Option, auf Basis der SAP-Entwicklungstools eine eigene Lösung zu entwickeln. Die wäre dann vernünftig im SAP-GUI integriert und den Datenaustausch per csv-könnte man sich auch sparen.


Vergiss es. Das wird in nächster Zeit nicht passieren. Ist aber auch egal und soll hier nicht das Thema sein. Ich möchte das Programm umsetzen, weil es ein sinnvolles Ziel ist und ich möchte es "gut" machen, weil ich "schöne" Software mag.


----------



## temi (5. Aug 2018)

AndiE hat gesagt.:


> So ist das noch nicht ideal. Vielleicht sagen dir "Lagerfachkarten" was. Im Prinzip heißt das, dass jede Entnahme zeitnah nachgewiesen wird. Diese wird dann anschließend verbucht. Sind Inhalte unter den Limit gesunken, werden dann neue zur Bestellung ausgeschrieben.
> 
> Daraus ergeben sich für mich diese Use-Cases:
> 1. Aufteilung: Zuerst kann man festlegen, welche Fächer es wo gibt.
> ...


Ehrlich gesagt, weiß ich nicht genau was du mir sagen möchtest. Soll ich einen Karteikasten kaufen?


----------



## temi (5. Aug 2018)

AndiE hat gesagt.:


> So ist das noch nicht ideal.


Kannst du das bitte begründen. *Was* ist nicht ideal und *warum*?


----------



## AndiE (5. Aug 2018)

Vielleicht habe ich auch einen Denkfehler. Ich würde mal einen "Schreibtischtest" durchführen. 
"Transport Timm liefert 10 Büchsen Farbe von "Bunt& Klar", 5 Rollen Kabel von "Elektro-Meier" und 5 Kisten Schrauben von "Schrauben-Paul". Diese Dinge werden in die Lagerfächer 1 bis 3 einsortiert. Am Ende des Tages sind 2 Büchsen Farbe entnommen, 1 Rolle Kabel und 1 Kiste Schrauben. Nach einer Woche sind nur noch 2 Dosen Farbe da- Sie muss nachbestellt werden."

Kann das Modell diese Vorgänge abbilden? Momentan ist es auch nicht sichtbar, wer was entnimmt, glaube ich. Ist das nicht wichtig? Soweit ich das sehe, kann die wichtige Frage: "Was haben wir noch an Material X an den 3 Standorten" nochjt geklärt werden.

Sorry, wenn ich falsch liege, aber das ist mein Eindruck.


----------



## mihe7 (5. Aug 2018)

AndiE hat gesagt.:


> Soweit ich das sehe, kann die wichtige Frage: "Was haben wir noch an Material X an den 3 Standorten" nochjt geklärt werden.



Zwischen StorageLocation und MaterialStock dürfte eine 1:n-Beziehung bestehen (die wäre im Diagramm falsch). Zwischen MaterialStock und Material eine n:1-Beziehung.

In SQL: SELECT location_id, material_id, sum(amount) FROM material_stock GROUP BY location_id, material_id;


----------



## mrBrown (5. Aug 2018)

mihe7 hat gesagt.:


> Ich denke, @mrBrown meinte mit "primitive Typen" etwas anderes als int usw. Es geht mehr darum, ob es sich um ein Attribut einer Klasse (bzw. deren Objekten) handelt, oder um Beziehungen. Das Alter einer Person kann man als Attribut der Klasse Person darstellen, egal ob man "int" oder eine "Age"-Klasse verwendet.
> 
> Gibt es dagegen eine Beziehung zu einer anderen Klasse, sagen wir mal Adresse, dann stellt man so etwas gerade in der Analyse nicht mehr als Feld dar. Erstens gehen die Multiplizitäten ggf. verloren, zweitens kann man die Beziehung dann nicht vernünftig beschreiben und drittens ist die Frage, ob im Entwurf die Beziehung tatsächlich noch so umgesetzt wird.
> 
> So sehe ich die Sache zumindest


Ja, so meinte ich das


----------



## temi (5. Aug 2018)

mihe7 hat gesagt.:


> Zwischen StorageLocation und MaterialStock dürfte eine 1:n-Beziehung bestehen


Das ist nicht richtig. Bei MaterialStock handelt es sich um die *lagerplatzbezogene* Menge, d.h. 1:1.


AndiE hat gesagt.:


> Kann das Modell diese Vorgänge abbilden?


Ich denke doch: Beim Einbuchen des Materials ist es nicht relevant, wer liefert oder von wem geliefert wurde. Das Material mit einer bestimmten Materialnummer wird in den (die) vorgesehenen Lagerorte/-plätze eingelagert und eingebucht. Entnahmen erfolgen analog. Wer das Material entnimmt oder einlagert ist nicht relevant, könnte aber in der *PostTransaction* erfasst werden, falls erforderlich.


AndiE hat gesagt.:


> Soweit ich das sehe, kann die wichtige Frage: "Was haben wir noch an Material X an den 3 Standorten" nochjt geklärt werden.


Standorte wären z.B. Werke. Das ist nicht vorgesehen und nicht erforderlich. Ich nehme an du meinst Lagerorte. Insofern bei einer Entnahme korrekt gebucht wurde, ist das abgedeckt.


----------



## temi (5. Aug 2018)

mrBrown hat gesagt.:


> Ja, so meinte ich das


Dann wäre das Modell ja in der Beziehung richtig, richtig?


----------



## mrBrown (5. Aug 2018)

temi hat gesagt.:


> Das ist nicht richtig. Bei MaterialStock handelt es sich um die *lagerplatzbezogene* Menge, d.h. 1:1.


Ja, aber in einem Lager kann es mehrere MaterialStocks geben, oder nicht?



temi hat gesagt.:


> PostTransaction


Was soll dies denn sein?


----------



## temi (5. Aug 2018)

mrBrown hat gesagt.:


> Ja, aber in einem Lager kann es mehrere MaterialStocks geben, oder nicht?


Ist das nicht durch die angegebene Multiplizität ausgedrückt?


mrBrown hat gesagt.:


> Was soll dies denn sein?


Laut LEO wäre "posting" eine mögliche Übersetzung für Warenbewegung. Ich nehme auch gerne eine bessere Bezeichnung. Movement? MoveTransaction?


----------



## mihe7 (5. Aug 2018)

temi hat gesagt.:


> Ist das nicht durch die angegebene Multiplizität ausgedrückt?


Nö. Zu einem MaterialStock gibt es einen Lagerplatz -> die 1 gehört auf die Seite von StorageLocation. Zu einem Lagerplatz gibt es mehrere MaterialStocks: auf Seite von MaterialStock müsste dann * (bzw. 0..*) stehen.


----------



## temi (5. Aug 2018)

mihe7 hat gesagt.:


> die 1 gehört auf die Seite von StorageLocation


Ist sie schon... (#48 - die hatte ich übersehen)


mihe7 hat gesagt.:


> Zu einem Lagerplatz gibt es mehrere MaterialStocks


Ich denke eher: Zu einem Material gibt es mehrere MaterialStocks und das steht doch auch da.
Oder verstehe ich hier generell etwas falsch?

Edit: Vielleicht gibt es ja für euch auch einen guten Grund, das von der anderen Seite zu sehen. Für mich ist das Material der zentrale Punkt.


----------



## temi (5. Aug 2018)

AndiE hat gesagt.:


> "Transport Timm liefert 10 Büchsen Farbe von "Bunt& Klar", 5 Rollen Kabel von "Elektro-Meier" und 5 Kisten Schrauben von "Schrauben-Paul". Diese Dinge werden in die Lagerfächer 1 bis 3 einsortiert.


Möglicherweise hast du doch recht damit, dass es nicht vollständig abgedeckt ist. Korrekt wäre, dass der Mitarbeiter, der die Einlagerung vornimmt, nach der offenen Bestellung sucht und diese im Zuge der Einlagerung abschließt. Das möchte ich aber erst mal verschieben, damit es nicht zu umfangreich wird an dieser Stelle.

Aber ich sehe das möglicherweise in einem anderen BoundedContext, oder? Möglicherweise sollte sogar Supplier, Manufacturer, Adress und Contact aus dem Kontext der Materialverwaltung entfernt werden. Ich habe das für die *Documentation* schon mal angedeutet. Wie seht ihr das?


----------



## mihe7 (5. Aug 2018)

Evtl. habe ich falsch übersetzt/interpretiert. Kannst Du (ggf. nochmal?) kurz schreiben, was StorageLocation und MaterialStock sein soll?


----------



## temi (5. Aug 2018)

mihe7 hat gesagt.:


> Evtl. habe ich falsch übersetzt/interpretiert. Kannst Du (ggf. nochmal?) kurz schreiben, was StorageLocation und MaterialStock sein soll?


Mach ich gern.
StorageLocation = Lagerort, z.B. Werkstatt EG, Werkstatt KG, Lager OG. I.d.R. werden die einmal am Anfang festgelegt und ändern sich dann nicht mehr.
MaterialStock = Lagerbestand mit Angabe des Lagerplatzes (z.B. Schrank 10 / Fach 3) bezogen auf einen bestimmten Lagerort.

Ein Material kann also mehrere Lagerbestände haben, die an unterschiedlichen Lagerorten untergebracht sind.

Im Diagramm ist da noch ein Fehler: Ein MaterialStock hat keinen "shortName" und keine "description".

Außerdem könnte theoretisch das Feld "amount" auch weggelassen werden, weil dieser aus den (noch so genannten) "PostTransactions" berechnet werden könnte. Ob das aber sinnvoll ist?


----------



## mihe7 (5. Aug 2018)

temi hat gesagt.:


> StorageLocation = Lagerort, z.B. Werkstatt EG, Werkstatt KG, Lager OG. I.d.R. werden die einmal am Anfang festgelegt und ändern sich dann nicht mehr.
> MaterialStock = Lagerbestand mit Angabe des Lagerplatzes (z.B. Schrank 10 / Fach 3) bezogen auf einen bestimmten Lagerort.


Gut, dann habe ich das schon richtig verstanden  und es gilt, was ich oben geschrieben habe: zwischen StorageLocation und MaterialStock gibt es eine 1:n-Beziehung.


----------



## temi (5. Aug 2018)

mihe7 hat gesagt.:


> Gut, dann habe ich das schon richtig verstanden  und es gilt, was ich oben geschrieben habe: zwischen StorageLocation und MaterialStock gibt es eine 1:n-Beziehung.


Gut, dann verstehe ich dich nicht. 



temi hat gesagt.:


> MaterialStock = Lagerbestand mit Angabe des Lagerplatzes (z.B. Schrank 10 / Fach 3) bezogen auf *einen* bestimmten Lagerort.


----------



## mrBrown (5. Aug 2018)

temi hat gesagt.:


> Gut, dann verstehe ich dich nicht.


An jeder StorageLocation gibt es *mehrere* MaterialStocks, jedes MaterialStocks ist aber in/gehört zu/wahtever *einer* StorageLocation:
`StorageLocation <>-1--*- MaterialStocks`




temi hat gesagt.:


> Außerdem könnte theoretisch das Feld "amount" auch weggelassen werden, weil dieser aus den (noch so genannten) "PostTransactions" berechnet werden könnte. Ob das aber sinnvoll ist?


Felder im Domänenmodell müssen nicht eins-zu-eins Feldern in den Klassen entsprechen 
MMn kann man das auch mit dieser Lösung umsetzen und entspricht trotzdem dem Modell.


----------



## temi (5. Aug 2018)

mrBrown hat gesagt.:


> An jeder StorageLocation gibt es *mehrere* MaterialStocks, jedes MaterialStocks ist aber in *einer* StorageLocation:
> StorageLocation <>-1--*- MaterialStocks



MaterialStock ist in keiner StorageLocation


Nicht ausgefüllte Raute = Aggregation

Die StorageLocation kann auch ohne einen MaterialStock bestehen. Der MaterialStock benötigt eine StorageLocation.

https://de.wikipedia.org/wiki/Klassendiagramm#Komposition_und_Aggregation

?

Ihr werft gerade mein ganzes Weltbild durcheinander


----------



## mrBrown (5. Aug 2018)

temi hat gesagt.:


> MaterialStock ist in keiner StorageLocation


Etwas doof formuliert von mir, aber sie entspricht doch dem Bestand von etwa *in* *einer* StorageLocation?




temi hat gesagt.:


> Nicht ausgefüllte Raute = Aggregation


Ja, in diesem Fall wäre aber Komposition besser (MaterialStock gibt es nicht ohne StorageLocation existieren) und die Beziehung müsste andersrum als in deinem Modell sein.


----------



## temi (5. Aug 2018)

mrBrown hat gesagt.:


> Ja, in diesem Fall wäre aber Komposition besser (MaterialStock gibt es nicht ohne StorageLocation existieren) und die Beziehung müsste andersrum als in deinem Modell sein.


Ich glaub ich trink jetzt erst mal ein Bier 

Also was ich ausdrücken möchte ist folgendes und ich formuliere es jetzt mal als Klasse:

Die Klasse MaterialStock enthält ein Feld vom Typ StorageLocation. Die Klasse StorageLocation weiß von MaterialStock gar nichts.

Was muss ich jetzt also dahin malen?

Komposition:


			
				Wikipedia hat gesagt.:
			
		

> Existenzabhängigkeit bedeutet, dass das _Ganze_ den Lebenszyklus der _Teile_ bestimmt, d. h. das Objekt, welches das _Ganze_ repräsentiert, übernimmt auch die Verantwortung für die Lebensdauer der Objekte, die seine _Teile_ repräsentieren. Wird das _Ganze_ gelöscht, verschwinden auch die Objekte, die zu diesem Zeitpunkt Bestandteil waren.



Darum hab ich Aggregation genommen, denn die StorageLocations existieren auch, wenn es überhaupt keine MaterialStocks gibt.

Lass ich einfach alle Rauten weg, dann habe ich eine Assoziation.


----------



## mrBrown (5. Aug 2018)

temi hat gesagt.:


> Also was ich ausdrücken möchte ist folgendes und ich formuliere es jetzt mal als Klasse:
> 
> Die Klasse MaterialStock enthält ein Feld vom Typ StorageLocation. Die Klasse StorageLocation weiß von MaterialStock gar nichts.


Das ist nicht das was du ausdrücken möchtest, sondern wie du es implementieren würdest 
Man macht es sich deutlich einfacher, wenn man solche Implementierungsdetails aus dem Modell ableitet, und nicht vorher festlegt und das Modell danach entwickelt, uU hat man dann nämlich völlig falsche Vorstellungen und macht es deutlich komplizierter als nötig.

Rein von dem Modell ausgehend würde ich es uU sogar andersrum implementieren, also Liste in StorageLocation 



temi hat gesagt.:


> Darum hab ich Aggregation genommen, denn die StorageLocations existieren auch, wenn es überhaupt keine MaterialStocks gibt.


Generell richtig, aber deine Aggregation drückt aktuell aus, das ein MaterialStock eine Aggregation von StorageLocations ist, also umgangssprachlich ein MaterialStock mehrere StorageLocations enthält.

Was du eigentlich meinst ist doch das Gegenteil: eine StorageLocations enthält mehrer eingelagerte Dinge (=Beziehung muss andersrum), und die MaterialStocks gibt es nur in einer StorageLocations, MaterialStock kann es nicht unabhängig davon geben (= Komposition).



Zum Modellieren würde mir das reichen:

Kardinalitäten würde ich dabei nur ergänzen, wenn sie nicht 1:n entsprechen.


----------



## temi (5. Aug 2018)

Es ist nicht einfach, nicht in Implementierungen zu denken, weil man sich im Hinterkopf fast immer überlegt, wie die Klassen und DB-Tabellen dazu aussehen könnten. In der Tat sind "meine" Domänenobjekte fast 1:1 aus meinen Gedanken zur Datenbank entsprungen (was ja einige Beiträge weiter vorne bereits mit Recht kritisiert wurde).



mrBrown hat gesagt.:


> Was du eigentlich meinst ist doch das Gegenteil: eine StorageLocation enthält mehrere eingelagerte Dinge



Müsste ich bei dieser Formulierung: "Ein Lager enthält mehrere eingelagerte Materialien" nicht ganz naiv so beginnen?



*MaterialStock* ist ja bereits ein Detail, das sich aus der Datenbank-Normalisierung ergeben hat (würde).

Wobei dann Komposition wieder falsch wäre, denn beide können zunächst mal unabhängig voneinander existieren, bis dem Material ein Lager zugeordnet wird.


----------



## temi (5. Aug 2018)

Vielen Dank übrigens noch einmal an alle, die sich an dieser, für mich sehr angenehm verlaufenden und äußerst lehrreichen Diskussion beteiligen! Ich nehme viele für mich sehr wertvolle Informationen mit.


----------



## mrBrown (5. Aug 2018)

temi hat gesagt.:


> Es ist nicht einfach, nicht in Implementierungen zu denken, weil man sich im Hinterkopf fast immer überlegt, wie die Klassen und DB-Tabellen dazu aussehen könnten. In der Tat sind "meine" Domänenobjekte fast 1:1 aus meinen Gedanken zur Datenbank entsprungen (was ja einige Beiträge weiter vorne bereits mit Recht kritisiert wurde).


Kenn ich, dass das manchmal schwierig ist 

Man muss es einfach immer wieder mal wegschieben, wenn man drüber nach denkt.
Mir wurde mal gesagt; Modellieren ist das schwierige, Implementiert bekommt man alles.

Und wenn du jetzt jemandem ohne Programmierkenntnisse das Modell erklären sollst, wird der dich bei „MaterialStock hat ein Feld von StorageLocation“ ziemlich dumm angucken - dabei ist das Verständis eigentlich der wesentliche Punkt 



temi hat gesagt.:


> Müsste ich bei dieser Formulierung: "Ein Lager enthält mehrere eingelagerte Materialien" nicht ganz naiv so beginnen?
> 
> 
> 
> ...


Ja, würde man wahrscheinlich - deshalb entwickelt man es iterative weiter 

Dabei fällt nämlich auf, das man jetzt gar keine Informationen über Mengen und Positionen, und man würde rein aus der Domäne schon ein zusätzliches Element dazwischen einfügen.
Es gibt ja auch in nem echten Lager mehr als nur das Lager und die Dinge die dein liegen. Vermutlich würd dann irgendein Lagerarbeiter drauf hinweisen, dass es eine Liste gibt, in der drin steht, wie viel wovon wo liegt oder so



temi hat gesagt.:


> Vielen Dank übrigens noch einmal an alle, die sich an dieser, für mich sehr angenehm verlaufenden und äußerst lehrreichen Diskussion beteiligen! Ich nehme viele für mich sehr wertvolle Informationen mit.


Für mich ist das auch lehrreich - es gibt keine Diskussionen, bei denen man nicht selbst auch was lernen würde 

Und grad Domänenmodelle kann man nur echt schwierig allein entwickeln, da ist sowas schon echt nötig


----------



## temi (5. Aug 2018)

Gut, wieder zurück zu den Wurzeln. Ich habe erst mal alles wieder etwas reduziert.




Ein Material hat eine Mengeneinheit zur Kalkulation der Bestände.

Ein Material kann mehrere Bestände (in verschiedenen Lagern) enthalten.
Es gibt ein oder mehrere unterschiedliche Lager.

Ein Lager kann Bestände von unterschiedlichen Materialien enthalten.
Die Bestände eines Materials können durch eine Transaktion geändert werden.
Ist das so einigermaßen korrekt modelliert?

Ist es sinnvoll den Kontext nur auf die Lagerhaltung des Materials zu begrenzen?

(Edit: Eine bessere Begrifflichkeit wäre vielleicht der der Teildomäne.)

Zum Material gehören noch weitere Daten, wie Lieferant, Hersteller, Hersteller-Materialnummer, die für das Material und für die Ein- und Auslagerung von Material nicht relevant sind. Diese würde ich daher in einen (oder mehrere) anderen Kontext (Edit: Teildomäne), z.B. "Order" verschieben.

Damit gehe ich für heute zum gemütlichen Teil über und wünsche euch allen noch einen angenehmen Sonntag!


----------



## AndiE (5. Aug 2018)

Wenn ich jetzt rein OO denke, dann habe ich diese Beziehungen:

Ein Lager enthält eine Liste seiner Lagerfächer.
Ein Lagerfach enthält die Art und die Anzahl der in ihm gelagerten Dinge.
Ein Lagerfach kann nur ein Material enthalten.
Ein Material kann sich in mehreren Lagerfächern befinden.
Ein Lager enthält eine Liste seiner Zweigstellen.
Eine Zweigstelle enthält eine Liste der Lagerfächer, die in ihr sind.

Das ist aber "falschherum":

Es müsste so sein:
Ein Lager enthält eine Liste der abgelegten Materialien.
Ein Material enthält eine Liste der Lagerfächer, wo es abgelegt ist
Ein Lagerfach kennt seinen Bestand an dem abgelegten Material.
Ein Lager enthält eine Liste seiner Zweigstellen.
Eine Zweigstelle enthält die Liste der Lagerfächer, die in ihm liegen.


----------



## temi (5. Aug 2018)

AndiE hat gesagt.:


> Es müsste so sein:
> Ein Lager enthält eine Liste der abgelegten Materialien.
> Ein Material enthält eine Liste der Lagerfächer, wo es abgelegt ist
> Ein Lagerfach kennt seinen Bestand an dem abgelegten Material.
> ...


Da ich in diesem Fall der Domänenspezialist bin (), kann ich dir an dieser Stelle sagen, dass es bei uns keine Zweigstellen gibt. Außerdem werden *Bestände* von *Material* nur auf *Lagerort*-Ebene betrachtet, nicht auf *Lagerplatz*-Ebene.

Da wir beide ja das gleiche Buch gelesen haben, habe ich die Begriffe der ubiquitären Sprache fett markiert. 

Mir fällt aber gerade auf, dass ich mich in #64 auch nicht dran gehalten habe. Böse.


----------



## mrBrown (5. Aug 2018)

AndiE hat gesagt.:


> Ein Material enthält eine Liste der Lagerfächer, wo es abgelegt ist


Hast du jemals irgendetwas in der Hand gehabt, und da stand drauf "ich liege in Fach 37A"?


----------



## temi (5. Aug 2018)

mrBrown hat gesagt.:


> Hast du jemals irgendetwas in der Hand gehabt, und da stand drauf "ich liege in Fach 37A"?


Es ist wirklich schwierig abzuschalten, wenn man sich gerade auf der Zielgerade wähnt...

Dein Kommentar hat mich dazu gebracht noch einmal nachzudenken.


temi hat gesagt.:


> Ein Material kann mehrere Bestände (in verschiedenen Lagern) enthalten.


Das klingt irgendwie falsch, weil ein Material keine Bestände enthält so wie es keine "Ablagefächer" enthält und damit wäre auch die Beziehung von Material zu Bestand (MaterialStock) falsch.

Ein Material hat eine Mengeneinheit zur Kalkulation der Bestände. 

?

Es gibt ein oder mehrere Lagerorte.

Ein Lagerort enthält Bestände von unterschiedlichem Material.
Bestände werden durch Ein- und Auslagerungen verändert
Vielleicht ist 2. auch nicht notwendig, weil bereits durch 4. abgedeckt. Wie ist aber die Beziehung zwischen Material und Bestand?


----------



## AndiE (5. Aug 2018)

Es ging mir vor allem um die Modellierung der Beziehungen zwischen den Objekten und Klassen.

So wie ich den TE verstanden habe, möchte der Bearbeiter wissen, wo welche Materialien liegen. Dabei war es für mich logisch, dass die Suchkette damit beginnt, dass in einem Objekt Lager, dem "Root-Objekt", eine Suche nach dem Material durchgeführt wird. Deshalb benötigt dieses Objekt Lager doch eine Liste der abgelegten Materialien (Klasse Material). In diesem Sinne wäre es doch schlau, wenn das Objekt Material eine Liste der Lagerplätze enthält, wo Bestände dieses Materials abgelegt ist. Suche ich "Waschbenzin", dann bekomme ich raus, dass "30 Liter an Stelle A3 " und "50 Liter auf an Stelle B4" sind. Ich habe auch überlegt, diesen Plätzen die Standorte (Boden, Werkstatt, Keller) zuzuordnen, aber ich bin dabei auf der n-Seite einer 1:n-Beziehung. Und das fand ich nicht so gut. Daher war ich dazu übergegangen, dass die Klasse Lager eine Liste der Standorte enthält, die wiederum die Liste der Lagerplätze enthält, die bei ihm sind.

Nun ist es recht egal, ob A3 (oder B4) eine abgekreidete Fläche beschreibt oder ein Fach in einem Schrank. Das ist zuerst zwar etwas umständlich umzusetzen, denn der Gabelstapler ist ja einfach da, aber dem muss trotzdem ein Standort zugewiesen werden, sonst platzt das Modell. 

Wenn der Lagerist weiß, dass sich 5 Kisten Schrauben M5x60 auf dem Boden befinden, dann hilft dem das wenig, wenn es dort 300 Meter Lagerfläche gibt. Das wäre schon die Suche einer Stricknadel im Heuhaufen. Ich glaube, da wäre dann eine genauere Festlegung des Ortes besser.


----------



## mrBrown (5. Aug 2018)

temi hat gesagt.:


> Wie ist aber die Beziehung zwischen Material und Bestand?


In dem Fall würde ich nur die Aggregation streichen (ist mir zugegebenerweise auch gar nicht aufgefallen, die ist so klein und versteckt...) und stattdessen an der Seite ein "1" ergänzen.



AndiE hat gesagt.:


> Es ging mir vor allem um die Modellierung der Beziehungen zwischen den Objekten und Klassen.


Relevant ist aber, dass es "konzeptionelle Klassen", und keine Klassen im Sinne des Java-Klassenbegriffs sind 




AndiE hat gesagt.:


> So wie ich den TE verstanden habe, möchte der Bearbeiter wissen, wo welche Materialien liegen. Dabei war es für mich logisch, dass die Suchkette damit beginnt, dass in einem Objekt Lager, dem "Root-Objekt", eine Suche nach dem Material durchgeführt wird. Deshalb benötigt dieses Objekt Lager doch eine Liste der abgelegten Materialien (Klasse Material). In diesem Sinne wäre es doch schlau, wenn das Objekt Material eine Liste der Lagerplätze enthält, wo Bestände dieses Materials abgelegt ist. Suche ich "Waschbenzin", dann bekomme ich raus, dass "30 Liter an Stelle A3 " und "50 Liter auf an Stelle B4" sind. Ich habe auch überlegt, diesen Plätzen die Standorte (Boden, Werkstatt, Keller) zuzuordnen, aber ich bin dabei auf der n-Seite einer 1:n-Beziehung. Und das fand ich nicht so gut. Daher war ich dazu übergegangen, dass die Klasse Lager eine Liste der Standorte enthält, die wiederum die Liste der Lagerplätze enthält, die bei ihm sind.


Das hat man doch bis auf unterschiedliche Lagerorte in einem Lager in seinem Modell schon gegeben.
Zwar nicht als direkte Beziehung, das wäre aber auch unsinnig und nur Redundanz.

Unterschiedliche Lagerorte sind, wenn ich ihn richtig verstanden habe, nicht nötig. Wenn doch, muss man das Modell natürlich leicht anpassen.

Wenn das Material irgendwas über die Lagerung weiß, bringt man nur wieder Zyklen rein, die immer Probleme machen.


----------



## mihe7 (6. Aug 2018)

temi hat gesagt.:


> *MaterialStock* ist ja bereits ein Detail, das sich aus der Datenbank-Normalisierung ergeben hat (würde).


Zwischen Lager und Material gibt es eine n:m-Beziehung (in einem Lager lagern verschiedene Materialien und "ein Material" kann in mehreren Lägern vorrätig sein). Damit ist die Beziehung jedoch nicht vollständig beschrieben, weil noch Details wie z. B. Mengen fehlen. Zu deren Beschreibung wird die Klasse MaterialStock eingeführt. In UML nennt man eine Klasse, die eine Beziehung konkretisiert übrigens association class, sähe dann etwa so aus:

​
Dabei stellt `{non-unique}` klar, dass die Beziehung zwischen StorageLocation und Material mehrfach vorkommen kann ("ein Material" kann in einem Lager in mehreren Lagerfächern gelagert sein).



AndiE hat gesagt.:


> So wie ich den TE verstanden habe, möchte der Bearbeiter wissen, wo welche Materialien liegen. Dabei war es für mich logisch, dass die Suchkette damit beginnt, dass in einem Objekt Lager, dem "Root-Objekt", eine Suche nach dem Material durchgeführt wird.


Das DDD-Modell ist kein Abfragemodell und sollte auch nicht als solches verwendet werden - sofern es nicht zufällig passt. 



temi hat gesagt.:


> Außerdem werden *Bestände* von *Material* nur auf *Lagerort*-Ebene betrachtet, nicht auf *Lagerplatz*-Ebene.


Wenn ich es richtig vestehe (Lagerort = StorageLocation = Lager und Lagerplatz = Lagerfach = StorageBin), dann stimmt etwas nicht:
1. entweder darf "ein Material" an verschiedenen Lagerplätzen gelagert sein, dann passt das Modell nicht zur zitierten Aussage, denn MaterialStock gibt den Bestand eines Materials je Lagerplatz an.
2. oder aber "ein Material" wird an einem Lagerort nur an einem einzigen Lagerplatz gelagert. Dann müsste im Diagramm oben {non-unique} entfernt werden.
Als dritte Alternative bliebe noch, dass die Aussage anders zu interpretieren ist.


----------



## temi (6. Aug 2018)

An einem Lagerort (= Lager) lagern verschiedene Materialien und ein Material wird an einem Lagerort nur an einem Lagerplatz gelagert. {non-unique} muss damit entfernt werden.

@mihe7 Danke!

Lagerort = Lager und Lagerplatz = Fach sind tatsächlich leicht verwirrend. Hilft aber nichts, die Begriffe werden bei uns genau so verwendet.


----------



## temi (6. Aug 2018)

Ich hätte nicht gedacht, dass sich das Domänenmodell solange hinziehen wird und hoffe, dass lässt nicht auf meine geistige Verfassung schließen 

Das ist der Stand: 

Soll "MaterialBooking" im Domänenmodell überhaupt auftauchen und wie ist die Assoziation?

Jetzt habe ich ein Domänenmodell und wie geht es jetzt weiter?

Aus dem Domänenmodell werden die Aggregates, Entities und ValueObjects modelliert. Dafür gibt es ein paar Faustregeln:

Fachliche Invarianten innerhalb der Aggregate-Grenzen
Kleine Aggregate
Referenz auf andere Aggregate nur über die Identität
Aktualisierung anderer Aggregate durch "eventual consistency"
Es ist also vermutlich eine dumme Idee alles in ein Aggregat "Material" zu packen (Regel 2).

Als ersten Schuss würde ich mal sagen:
Aggregates: Material, StorageLocation
ValueObject: QuantityUnit

Bei MaterialStock bin ich mir nicht sicher. In der DB hat es sicher eine Id, aber wie und in welchen Tabellen die Daten des Modells in der DB abgebildet werden ist hier vermutlich völlig unerheblich. Ich würde MaterialStock vielleicht eher als ValueObject sehen und in einem der beiden Aggregate unterbringen.


----------



## mihe7 (6. Aug 2018)

temi hat gesagt.:


> Ich hätte nicht gedacht, dass sich das Domänenmodell solange hinziehen wird und hoffe, dass lässt nicht auf meine geistige Verfassung schließen


Nein, nein...  Spaß bei Seite: das Problem ist einfach, dass wir alle unterschiedliche Voraussetzungen und Vorstellungen haben. @AndiE scheint z. B. fachlich im Thema zu stecken, ich dagegen habe mit Lagerverwaltung in der Form gar nichts am Hut. Außerdem waren die Begrifflichkeiten abzuklären. Dann darf man nicht vergessen, dass wir uns nicht gegenübersitzen. Hält natürlich auch auf. Außerdem ist "lange" relativ. Das kenne ich ganz anders: wenn genügend Leute meinen, beteiligt sein zu müssen, dann sind da Monate(!) teilweise nichts :-( 


temi hat gesagt.:


> Lagerort = Lager und Lagerplatz = Fach sind tatsächlich leicht verwirrend. Hilft aber nichts, die Begriffe werden bei uns genau so verwendet.


Das ist kein Problem - alles nur aneinandergereihte Buchstaben. Man muss sich nur einig werden.

Jetzt muss ich nochmal rückfragen: wir wissen jetzt, dass ein Material immer nur an einem Lagerplatz liegen kann, wie sieht es umgekehrt aus? Kann an einem Lagerplatz verschiedenes Material liegen?


----------



## temi (6. Aug 2018)

mihe7 hat gesagt.:


> Jetzt muss ich nochmal rückfragen: wir wissen jetzt, dass ein Material immer nur an einem Lagerplatz liegen kann, wie sieht es umgekehrt aus? Kann an einem Lagerplatz verschiedenes Material liegen?



Ja, weil der Lagerplatz nur eine Art Hilfe ist um Material schneller finden zu können. Der Lagerplatz ist einfach nur ein Freitext. Er kann genauso "Schrank 5" lauten als auch "bei Meier in der Werkbank" und ist also nicht auf eine vorgegebene Menge begrenzt. Lagerorte sind vorgegeben und müssen aus einer gegebenen Menge ausgewählt werden (die natürlich auch erweitert werden kann => Stammdatenverwaltung).



> Außerdem werden *Bestände* von *Material* nur auf *Lagerort*-Ebene betrachtet, nicht auf *Lagerplatz*-Ebene.



Es gibt *einen* (Material-) Bestand für jeden Lagerort, an dem das Material gelagert wird.
Da der Lagerplatz (storageBin) ein Feld von Bestand ist, kann es dadurch nur einen Lagerplatz pro Lagerort für einen Bestand geben.

Und damit noch mal zur obigen Frage: Es kann natürlich für unterschiedliche Materialbestände der gleiche "Schrank" angegeben werden. "storageBin" ist nur ein Feld im Bestand ohne Bezug zu irgend einer Klasse außerhalb.

Edit: Vielleicht wäre es von Anfang an besser gewesen, den Begriff "Lagerplatz" aus der Beschreibung heraus zu lassen, um Verwirrung zu vermeiden. Ich werde das Feld von "storageBin" in "storageBinInfo" umbenennen, um den Charakter deutlicher hervorzuheben.


----------



## mrBrown (6. Aug 2018)

Ich würde in dem Fall auch den Lagerplatz auch explizit modellieren


----------



## temi (6. Aug 2018)

mrBrown hat gesagt.:


> Ich würde in dem Fall auch den Lagerplatz auch explizit modellieren


Weil er eine wichtige fachliche Information darstellt und im Modell nicht untergehen darf, oder warum sonst?

Deine Aussage ist ja ungefähr entgegen gesetzt zu meiner (was keine Bewertung sein soll):


temi hat gesagt.:


> Vielleicht wäre es von Anfang an besser gewesen, den Begriff "Lagerplatz" aus der Beschreibung heraus zu lassen, um Verwirrung zu vermeiden.


----------



## AndiE (6. Aug 2018)

Noch mal eine Nachfrage: Für mich ist ein Lager eine Einrichtung mit einem Tresen. Man gibt seine Materialanforderung rein und bekommt vom Lagerverwalter sein Material ausgehändigt. Hinter dem Tresen befindet sich der Lagerraum in dem sich viele Regale etc. befinden, worin die Dinge liegen, die man anfordern kann. In diesem Falle wären das drei Lager, die z.B. nach Stoffart unterschieden sind: Flüssigkeitslager( Farben, Farbstoffe) und Außenlager für große Dinge wie Bretter, Kisten, Tröge. Wenn von etwas etwas fehlt, wird es angefordert und vom Lagerververwalter, der hinter dem Tresen tätig ist, eingelagert.

Neben diesem (Zentral-)Lager gibt es an den Arbeitsplätzen noch (Hand-)Lager. Fehlt einem Mitarbeiter etwas, oder geht zur Neige, dann füllt er den Bestand aus dem Lager auf.

@temi: Ich glaube, du meinst das nicht so, wie ich das geschildert habe, nicht?


----------



## temi (6. Aug 2018)

AndiE hat gesagt.:


> Ich glaube, du meinst das nicht so, wie ich das geschildert habe, nicht?


Also einen Tresen muss es nicht unbedingt geben und auch keinen Lageristen .
Wer einen Artikel entnimmt oder einlagert ist auch nicht relevant bzw. kann ggf. über Berechtigungen beschränkt werden.

Für diese Domäne ist ein Lagerort nur ein "Ding" auf dem bezogen ein Materialbestand verwaltet werden kann.

Ein realer Lagerort kann ein Gebäude sein, ein Raum oder ein Schrank/Regal, je nachdem wie man es definiert. Entscheidend ist nur das Bestände bezogen auf einen Lagerort verwaltet werden können.

In *dieser* Domäne ist der Lagerort die *einzige* Ebene auf der Bestände verwaltet werden können.

Denkbar wären als übergeordnete Ebene das "Werk" = Werksbestand und als darunter liegende Ebene der "Lagerplatz" = Lagerplatzbestand. Beides ist *hier* nicht gefordert.


----------



## mrBrown (6. Aug 2018)

temi hat gesagt.:


> Weil er eine wichtige fachliche Information darstellt und im Modell nicht untergehen darf, oder warum sonst?
> 
> Deine Aussage ist ja ungefähr entgegen gesetzt zu meiner (was keine Bewertung sein soll):


Ja, ist schließlich ein vorkommendes Konzept, da wäre es besser als wirkliche Klasse, als nur als Attribut aufgehoben 

Die Verwirrung kam ja in dem Fall zT durch fehlendes Verständniss, da hätte das mMn schon geholfen.


----------



## AndiE (6. Aug 2018)

Ich bin jetzt schon beim nächsten Schritt, dem Bildung der Aggregate. Ich möchte nun wissen, wie es zu einer Bestellung kommt. Wenn es keinen Lagerverwalter gibt, wäre auch das System denkbar, wie man es zu Hause macht.

Monteur benötigt Material->(Monteur sieht)Das Material geht zur Neige->(PC)Ist noch was vorhanden?->JA->Lagerort suchen->(benötigtes Material umlagern)->Material neubestellen->(Auf Lieferung warten)->Material einbuchen

An Stelle PC würde man die Lagerverwaltung anwerfen und damit arbeiten. 

Im Prinzip ist dann hier die Größe des Bestandes egal. Da reicht auch eine Ampel: grün- genügend; gelb-wird eng; rot nur noch einige Reste.


----------



## mrBrown (6. Aug 2018)

AndiE hat gesagt.:


> Ich bin jetzt schon beim nächsten Schritt, dem Bildung der Aggregate.


Dann mach das doch, statt einen Use-Case und dessen Implementierungsdetails zu erklären


----------



## AndiE (6. Aug 2018)

Dazu brauche ich das OK des Fachexperten. Erst dann kann ich die "Domain Events" festlegen und dazwischen die Aggregate anlegen.


----------



## temi (6. Aug 2018)

AndiE hat gesagt.:


> Dazu brauche ich das OK des Fachexperten. Erst dann kann ich die "Domain Events" festlegen und dazwischen die Aggregate anlegen.


Bestellungen werden von der Teildomäne "Materiallager" nicht abgedeckt. Hatte ich auch ein paar Beiträge weiter oben schon mal geschrieben. Damit das hier nicht zu groß wird sollten wir uns darauf beschränken. Meine Meinung.


----------



## AndiE (6. Aug 2018)

1. check empty items->EmptyItemsChecked
2. check storage location->StorageLocationChecked
3. Move Items-> Items Moved
4. Require Items->Items Required

Vorbehaltlich, dass ich jetzt völlig falsch liege. 
Im ersten Aggregat werden alle leeren Fächer gesammelt und zu einer Liste/Tabelle zusammengefügt. 

Im zweiten Aggregat wird kontrolliert, ob diese Dinge noch irgendwo vorhanden sind. Es werden zwei Tabellen erstellt: Eine mit Dingen die doppelt vorhanden sind und eine mit denen, die nicht mehr weiter vorhanden sind.

Im dritten Aggregat wird eine Liste erzeugt, wo noch Dinge zu finden sind. Werden sie bewegt, verändert sich ja ihr Lagerort.

Im vierten Aggregat wird eine Liste erstellt, was neu zu besorgen ist. Hier ist dann die Schnittstelle zum Bestellwesen.


----------



## mihe7 (6. Aug 2018)

temi hat gesagt.:


> Soll "MaterialBooking" im Domänenmodell überhaupt auftauchen und wie ist die Assoziation?


Die Domäne dürfte "Lagerverwaltung" sein - von daher ja. Die Buchung gibt an, in welchem Lager bezogen auf welches Material ein Zu- oder Abgang erfolgte (zzgl. ggf. weiterer Details, wer, wann, ...) 

Das Lager "führt die Buchung durch", indem es den betreffenden Bestand verwaltet. Würde m. E. zumindest aktuell sinnvoll erscheinen. Schauen wir mal.

Aggregate (aggregate roots fett): 
1. *StorageLocation* und MaterialStock
2. *Material*
3. *MaterialBooking*

MaterialStock hat über das Material eine lokale Identität innerhalb der StorageLocation. Material weiß nichts vom Rest. Die Buchung gibt eine Referenz auf die StorageLocation und das Material an. D. h. anhand der Buchung kann die StorageLocation ermittelt werden. Dieser kann die Buchung zur "Durchführung" übergeben werden. Die StorageLocation kann anhand der in der Buchung angegebenen Referenz zum Material den Lagerplatz ermitteln, Geschäftsregeln durchsetzen usw. Hört sich zumindest für mich im ersten Moment nicht schlecht an.


----------



## temi (7. Aug 2018)

mihe7 hat gesagt.:


> Aggregate (aggregate roots fett):
> 1. *StorageLocation* und MaterialStock
> 2. *Material*
> 3. *MaterialBooking*





mihe7 hat gesagt.:


> MaterialStock hat über das Material eine lokale Identität innerhalb der StorageLocation.
> 
> Material weiß nichts vom Rest.
> 
> ...



Gibt es eine Fausregel, wie man hier generell vorgeht?

StorageLocation und Material haben eine natürliche Identität durch die StorageLocationId und die MaterialId. Beide Identitäten sind für den User zur Verwendung der Lagerverwaltung notwendig (z.B. Beschriften der Fächer mit der Materialnummer).

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?

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?

StorageBin ist ein ValueObject und gehört zu MaterialStock.


----------



## temi (7. Aug 2018)

mihe7 hat gesagt.:


> kann [...], Geschäftsregeln durchsetzen usw.


Wo werden denn die Geschäftsregeln beschrieben?
Die gehören doch auch irgendwie zum Domänenmodell und ergeben sich nicht vollständig z.B. aus Multiplizitäten.


----------



## AndiE (7. Aug 2018)

@mihe7: Wie soll das funktionieren? Nach dem Buch habe ich eine Kette von Commands-Aggregat-Events-Commands-Aggregat.


----------



## mihe7 (7. Aug 2018)

@temi Antwort kommt später, hab gerade keine Zeit. Geschäftsregel ist z. B. dass Material an einem Lagerort nur an einem Lagerplatz liegen darf.

@AndiE was meinst Du?


----------



## mrBrown (7. Aug 2018)

AndiE hat gesagt.:


> @mihe7: Wie soll das funktionieren? Nach dem Buch habe ich eine Kette von Commands-Aggregat-Events-Commands-Aggregat.


wenn du dich auf einzelne Antworten beziehst, wird es deutlich verständlicher, wenn du die entsprechenden Teile zitierst


----------



## temi (7. Aug 2018)

mihe7 hat gesagt.:


> Antwort kommt später, hab gerade keine Zeit.


Kein Ding.


mihe7 hat gesagt.:


> Geschäftsregel ist z. B. dass Material an einem Lagerort nur an einem Lagerplatz liegen darf.


Es geht mehr darum, ob die Geschäftsregeln irgendwie im Domänenmodell dokumentiert werden, z.B. eine Liste irgendwo am Rand. Sprich: Sollte das Domänenmodell so vollständig sein, dass sich alle Geschäftsregeln und was es sonst noch so gibt daraus lesen lassen?


----------



## AndiE (7. Aug 2018)

mihe7 hat gesagt.:


> Aggregate (aggregate roots fett):
> 1. *StorageLocation* und MaterialStock
> 2. *Material*
> 3. *MaterialBooking*



Wie bekommt man dem nun Leben eingehaucht? Dazu würde ich gerne wissen, wie das System angewendet werden soll. Momentan würde ich das so sehen:

START->Bearbeiter sucht nach einem Material-> 1. Ist das Material im System vorhanden?-JA->Bearbeiter sucht nach Ort, wo er das Material finden kann->2. Will der Mitarbeiter Material entnehmen?->JA->3. Ist das Material noch ausreichend vorhanden?->JA->ENDE

1. NEIN->Material neu in Bestand aufnehmen
2. NEIN->Material datentechnisch in Bestand einfügen. Physisch an Stelle ablegen.
3. NEIN->Auf Wunschliste schreiben.

Könnte man das so nehmen?


----------



## mrBrown (7. Aug 2018)

AndiE hat gesagt.:


> Wie bekommt man dem nun Leben eingehaucht?


Indem man eine Anwendung drum rum baut, nur das Modell hat natürlich erstmal kein "Leben".
Aber alles, was du für deinen Use-Case unten brauchst, ist im Modell vorhanden.



AndiE hat gesagt.:


> Dazu würde ich gerne wissen, wie das System angewendet werden soll. Momentan würde ich das so sehen:
> 
> START->Bearbeiter sucht nach einem Material-> 1. Ist das Material im System vorhanden?-JA->Bearbeiter sucht nach Ort, wo er das Material finden kann->2. Will der Mitarbeiter Material entnehmen?->JA->3. Ist das Material noch ausreichend vorhanden?->JA->ENDE
> 
> ...


Das klingt zumindest nicht gänzlich falsch...


----------



## mihe7 (7. Aug 2018)

temi hat gesagt.:


> Sollte das Domänenmodell so vollständig sein, dass sich alle Geschäftsregeln und was es sonst noch so gibt daraus lesen lassen?



Das kommt jetzt darauf an, was wir unter Domänenmodell verstehen wollen. Das Domain Model als Teil der Software muss die Geschäftsregeln natürlich irgendwie abbilden. Bei den Diagrammen zum Domain Model finde ich, wäre es übertrieben, wenn wirklich jeder "Mist" dargestellt werden würde.  

Ich würde auch z. B. keine explizite MaterialStockAmountMustNotBeNegative-Rule einführen  Dass ein Bestand nicht negativ werden kann, ist invariant und wird sich auch künftig nicht ändern.



AndiE hat gesagt.:


> 1. Ist das Material im System vorhanden?


Das DDD-Modell ist oft zu komplex, um es als Query-Model gebrauchen zu können. Diese Info würde man aber ggf. sogar noch direkt über das Material-Repository bekommen.



AndiE hat gesagt.:


> Material neu in Bestand aufnehmen


Material-Repository



AndiE hat gesagt.:


> Material datentechnisch in Bestand einfügen.


Bestand einbuchen.



AndiE hat gesagt.:


> Auf Wunschliste schreiben.


Post-it


----------



## mrBrown (7. Aug 2018)

mihe7 hat gesagt.:


> Das kommt jetzt darauf an, was wir unter Domänenmodell verstehen wollen. Das Domain Model als Teil der Software muss die Geschäftsregeln natürlich irgendwie abbilden. Bei den Diagrammen zum Domain Model finde ich, wäre es übertrieben, wenn wirklich jeder "Mist" dargestellt werden würde.
> 
> Ich würde auch z. B. keine explizite MaterialStockAmountMustNotBeNegative-Rule einführen  Dass ein Bestand nicht negativ werden kann, ist invariant und wird sich auch künftig nicht ändern.


Wobei es oftmals praktisch ist, relevante Dinge irgendwie als Notiz dranzuhängen, sollte natürlich nicht zu viel werden.

Sowas wie "MaterialStockAmountMustNotBeNegative" würde ich einfach über einen nicht-negativen Datentypen abbilden


----------



## mihe7 (7. Aug 2018)

mrBrown hat gesagt.:


> einfach über einen nicht-negativen Datentypen abbilden


Der heißt dann aber nicht MaterialStockAmountMustNotBeNegative


----------



## temi (8. Aug 2018)

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. 

Möglicherweise werden sich viele noch offene Fragen auch (fast) von selbst lösen; das Buch "DDD kompakt" wurde hier bereits erwähnt. Meiner Meinung nach ist das Buch ziemlich überflüssig, weil es zu viele Fragen offen lässt, bzw. ständig auf das Buch "Implementing DDD" von Vernon verweist. Genau dieses Buch habe ich mir jetzt zugelegt und auf den ersten Blick wird hier deutlich detaillierter und mit vielen Beispielen auf das Thema eingegangen. Mehr werde ich allerdings erst wissen, wenn ich mit dem Lesen fertig bin.

Gruß,
temi


----------



## AndiE (8. Aug 2018)

Im Buch hilft Kapitel 5 schon etwas, wie man Entitys entwickelt. Ich würde aber auch ohne Buch nun weitergehen und eine erste Implementierung versuchen. Dabei finde ich es wichtig, sich auf das Wesentliche zu konzentrieren. Die solltest dir ziemlich einfach einen Lagerbestand aufbauen. In etwa so:


```
...
List ml= new List<Material>();
Material m1=  new Material(1,"Stahl","m");
//ID, name, messure
ml.add(m1);
// Das ganze ein paar Mal

List sl= new List<StorageLocation>();
StorageLocation st=new StorageLocation(1,"Keller");
//id, description
sl.add(st);

usw.
```

Der Sinn dahinter ist, dass du dir aufgrund deines Modells ein Dummy-Lager aufbaust. Nun fehlt noch die m:n-Beziehung mit der Beziehungsklasse, mit der du dein Lager füllst. 

Dann kannst du im nächsten Schritt mal die Anwendung durchspielen.


----------



## temi (8. Aug 2018)

AndiE hat gesagt.:


> Ich würde aber auch ohne Buch nun weitergehen und eine erste Implementierung versuchen.


Um die Implementierung geht es mir hier eigentlich gar nicht so sehr, sondern nur um die Architektur des Systems und da hab ich schon noch einige Fragen, die mir unter den Nägeln brennen. Es soll in diesem Thema auch keine vollständige Anwendung rausfallen, es geht mir um den Weg dahin und vielleicht ein paar "best practices" (ganz am Schluss soll natürlich eine funktionierende Anwendung stehen, aber die muss ich hier nicht komplett diskutieren). Wir können das aber gerne später unter uns diskutieren, wenn es dich interessiert.


----------



## AndiE (8. Aug 2018)

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.


----------



## mrBrown (8. Aug 2018)

temi hat gesagt.:


> 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?



temi hat gesagt.:


> 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  




AndiE hat gesagt.:


> 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"?


----------



## AndiE (8. Aug 2018)

"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.


----------



## mrBrown (8. Aug 2018)

AndiE hat gesagt.:


> "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


----------



## temi (8. Aug 2018)

mrBrown hat gesagt.:


> 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.



mrBrown hat gesagt.:


> 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...


----------



## mrBrown (8. Aug 2018)

temi hat gesagt.:


> 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...



temi hat gesagt.:


> 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?


----------



## temi (8. Aug 2018)

mrBrown hat gesagt.:


> 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.


----------



## mrBrown (9. Aug 2018)

temi hat gesagt.:


> 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


----------



## mihe7 (9. Aug 2018)

temi hat gesagt.:


> 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 



temi hat gesagt.:


> 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.



temi hat gesagt.:


> 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.



temi hat gesagt.:


> Ä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


----------



## temi (9. Aug 2018)

mrBrown hat gesagt.:


> 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?



mihe7 hat gesagt.:


> Oops, ja das bin ich noch schuldig


Von mir gibt's keine Schuldzuweisungen 



mihe7 hat gesagt.:


> 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!


mihe7 hat gesagt.:


> 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.


----------



## mrBrown (9. Aug 2018)

temi hat gesagt.:


> Das ist doch einigermaßen korrekt?


Ja, sinnvoll ist es schon, dass beides explizit zu modellieren 



temi hat gesagt.:


> 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?


----------



## temi (9. Aug 2018)

mrBrown hat gesagt.:


> Die Zusammengesetzte ID würde bedeuten, dass ein Material nur maximal einmal an jeder Storage-Location liegen darf.


Das passt schon so. Bestand wird auf Lagerortebene verwaltet nicht auf Lagerplatzebene.



mrBrown hat gesagt.:


> Nur Aggregate-Roots müssen eine "globale" Identität haben, für alle reicht innerhalb des Aggregate-Roots eindeutig


Danke für die Klärung!


----------



## temi (9. Aug 2018)

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?


----------



## mrBrown (9. Aug 2018)

temi hat gesagt.:


> 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...



temi hat gesagt.:


> 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


----------



## mrBrown (9. Aug 2018)

temi hat gesagt.:


> Das ist "normale" Klassendefinition, oder? Mit öffentlichen Methoden, die die Geschäftsvorfälle abbilden?


Ja


----------



## temi (9. Aug 2018)

mrBrown hat gesagt.:


> Also hat MaterialStock mittlerweile keine "storageBin(Info)" mehr, die sollte dich einen Lagerplatz innerhalb des Lagerortes angeben?


Doch, die hat es weiterhin, aber sie ist nur ein Hinweis, wo das Material am Lagerort genau zu finden ist. "StorageBin" ist KEINE weitere Verwaltungsebene für Bestände!


----------



## mihe7 (9. Aug 2018)

Mal in Code:

```
public class StorageLocation{
    private Map<MaterialId, MaterialStock> stocks;
}
```



temi hat gesagt.:


> aber sie ist nur ein Hinweis, wo das Material am Lagerort genau zu finden ist.


Das obligatorische Kommentarfeld für den Anwender


----------



## mrBrown (9. Aug 2018)

temi hat gesagt.:


> 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?


----------



## temi (9. Aug 2018)

mrBrown hat gesagt.:


> 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".


----------



## mrBrown (9. Aug 2018)

temi hat gesagt.:


> 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.


----------



## temi (9. Aug 2018)

mrBrown hat gesagt.:


> 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.


----------



## temi (9. Aug 2018)

Der Domainlayer könnte dann ungefähr folgendermaßen aussehen:
 
Wobei ein domain service Vorfälle übernimmt, die ein einzelnes Aggregat nicht allein abdecken kann. Richtig?


----------



## mrBrown (9. Aug 2018)

temi hat gesagt.:


> 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".




temi hat gesagt.:


> Wobei ein domain service Vorfälle übernimmt, die ein einzelnes Aggregat nicht allein abdecken kann. Richtig?


Ja, genau.


----------



## temi (9. Aug 2018)

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.

 




temi hat gesagt.:


> aber auch von einem Lagerort zu einem anderen Lagerort



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


----------

