Warum den Datenzugriff trennen?
Aus dem Buch denke ich, dass die ersten beiden Seiten des Kapitels Model Driven Design eine Rechtfertigung dafür liefern, warum Sie technische Implementierungsdetails aus der Implementierung des Domänenmodells abstrahieren möchten.
- Sie möchten eine enge Verbindung zwischen dem Domänenmodell und dem Code aufrechterhalten
- Die Trennung technischer Belange hilft zu beweisen, dass das Modell für die Implementierung praktisch ist
- Sie möchten, dass die allgegenwärtige Sprache das Design des Systems durchdringt
Dies scheint alles zu dem Zweck zu sein, ein separates "Analysemodell" zu vermeiden, das von der tatsächlichen Implementierung des Systems getrennt wird.
Nach meinem Verständnis des Buches kann dieses "Analysemodell" ohne Berücksichtigung der Softwareimplementierung entworfen werden. Sobald Entwickler versuchen, das von der Unternehmensseite verstandene Modell zu implementieren, bilden sie aufgrund der Notwendigkeit ihre eigenen Abstraktionen, was zu einer Mauer in der Kommunikation und im Verständnis führt.
In der anderen Richtung können Entwickler, die zu viele technische Probleme in das Domänenmodell einbringen, ebenfalls diese Kluft verursachen.
Sie könnten also in Betracht ziehen, dass das Üben der Trennung von Bedenken wie z. B. Persistenz dazu beitragen kann, sich vor diesen unterschiedlichen Entwurfs- und Analysemodellen zu schützen. Wenn es notwendig erscheint, Dinge wie Persistenz in das Modell einzuführen, ist dies eine rote Fahne. Möglicherweise ist das Modell für die Implementierung nicht praktisch.
Zitat:
"Das einzelne Modell verringert die Fehlerwahrscheinlichkeit, da das Design jetzt ein direktes Ergebnis des sorgfältig überlegten Modells ist. Das Design und sogar der Code selbst haben die Kommunikationsfähigkeit eines Modells."
So wie ich das interpretiere, verlieren Sie diese Kommunikationsfähigkeit, wenn Sie mehr Codezeilen haben, die sich mit Dingen wie dem Datenbankzugriff befassen.
Wenn Sie beispielsweise auf die Überprüfung der Eindeutigkeit zugreifen müssen, schauen Sie sich Folgendes an:
Udi Dahan: Die größten Fehler, die Teams bei der Anwendung von DDD machen
http://gojko.net/2010/06/11/udi-dahan-the-biggest-mistakes-teams-make-when-applying-ddd/
unter "Alle Regeln sind nicht gleich"
und
Verwenden des Domänenmodellmusters
http://msdn.microsoft.com/en-us/magazine/ee236415.aspx#id0400119
unter "Szenarien für die Nichtverwendung des Domänenmodells", in denen dasselbe Thema behandelt wird.
So trennen Sie den Datenzugriff
Laden von Daten über eine Schnittstelle
Die "Datenzugriffsschicht" wurde über eine Schnittstelle abstrahiert, die Sie aufrufen, um die erforderlichen Daten abzurufen:
var orderLines = OrderRepository.GetOrderLines(orderId);
foreach (var line in orderLines)
{
total += line.Price;
}
Vorteile: Die Schnittstelle trennt den Installationscode "Datenzugriff", sodass Sie weiterhin Tests schreiben können. Der Datenzugriff kann von Fall zu Fall abgewickelt werden, was eine bessere Leistung als eine generische Strategie ermöglicht.
Nachteile: Der aufrufende Code muss davon ausgehen, was geladen wurde und was nicht.
Angenommen, GetOrderLines gibt aus Leistungsgründen OrderLine-Objekte mit einer ProductInfo-Null-Eigenschaft zurück. Der Entwickler muss den Code hinter der Schnittstelle genau kennen.
Ich habe diese Methode auf realen Systemen ausprobiert. Am Ende ändern Sie ständig den Umfang der geladenen Daten, um Leistungsprobleme zu beheben. Am Ende spähen Sie hinter die Benutzeroberfläche, um den Datenzugriffscode zu überprüfen und festzustellen, was geladen wird und was nicht.
Die Trennung von Bedenken sollte es dem Entwickler nun ermöglichen, sich so weit wie möglich auf einen Aspekt des Codes zu konzentrieren. Die Schnittstellentechnik entfernt das WIE werden diese Daten geladen, aber nicht WIE VIEL Daten werden geladen, WENN sie geladen werden und WO sie geladen werden.
Fazit: Ziemlich geringe Trennung!
Faules Laden
Daten werden bei Bedarf geladen. Aufrufe zum Laden von Daten sind im Objektdiagramm selbst ausgeblendet. Wenn Sie auf eine Eigenschaft zugreifen, kann eine SQL-Abfrage ausgeführt werden, bevor das Ergebnis zurückgegeben wird.
foreach (var line in order.OrderLines)
{
total += line.Price;
}
Vorteile: Das "WANN, WO und WIE" des Datenzugriffs ist dem Entwickler verborgen, der sich auf die Domänenlogik konzentriert. Das Aggregat enthält keinen Code, der sich mit dem Laden von Daten befasst. Die geladene Datenmenge kann genau der Menge entsprechen, die der Code benötigt.
Nachteile: Wenn Sie von einem Leistungsproblem betroffen sind, ist es schwierig, es zu beheben, wenn Sie eine generische "Einheitslösung" haben. Das verzögerte Laden kann insgesamt zu einer schlechteren Leistung führen, und das Implementieren des verzögerten Ladens kann schwierig sein.
Rollenschnittstelle / Eifriges Abrufen
Jeder Anwendungsfall wird über eine von der Aggregatklasse implementierte Rollenschnittstelle explizit angegeben , sodass Datenladestrategien pro Anwendungsfall verarbeitet werden können.
Die Abrufstrategie kann folgendermaßen aussehen:
public class BillOrderFetchingStrategy : ILoadDataFor<IBillOrder, Order>
{
Order Load(string aggregateId)
{
var order = new Order();
order.Data = GetOrderLinesWithPrice(aggregateId);
return order;
}
}
Dann kann Ihr Aggregat wie folgt aussehen:
public class Order : IBillOrder
{
void BillOrder(BillOrderCommand command)
{
foreach (var line in this.Data.OrderLines)
{
total += line.Price;
}
etc...
}
}
Die BillOrderFetchingStrategy wird verwendet, um das Aggregat zu erstellen, und dann erledigt das Aggregat seine Arbeit.
Vorteile: Ermöglicht benutzerdefinierten Code pro Anwendungsfall und ermöglicht so eine optimale Leistung. Entspricht dem Prinzip der Schnittstellentrennung . Keine komplexen Code-Anforderungen. Aggregat-Unit-Tests müssen die Ladestrategie nicht nachahmen. In den meisten Fällen kann eine generische Ladestrategie verwendet werden (z. B. eine "Alle laden" -Strategie), und bei Bedarf können spezielle Ladestrategien implementiert werden.
Nachteile: Der Entwickler muss die Abrufstrategie nach dem Ändern des Domänencodes noch anpassen / überprüfen.
Beim Ansatz der Abrufstrategie ändern Sie möglicherweise immer noch den benutzerdefinierten Abrufcode, um die Geschäftsregeln zu ändern. Es ist keine perfekte Trennung von Bedenken, wird aber am Ende wartbarer und ist besser als die erste Option. Die Abrufstrategie kapselt die Daten WIE, WANN und WO. Es hat eine bessere Trennung von Bedenken, ohne an Flexibilität zu verlieren, wie die Einheitsgröße für alle Lazy-Loading-Ansätze.