Pourquoi séparer l'accès aux données?
D'après le livre, je pense que les deux premières pages du chapitre Model Driven Design expliquent pourquoi vous voulez faire abstraction des détails techniques d'implémentation de l'implémentation du modèle de domaine.
- Vous souhaitez garder un lien étroit entre le modèle de domaine et le code
- Séparer les problèmes techniques permet de prouver que le modèle est pratique pour la mise en œuvre
- Vous voulez que le langage omniprésent imprègne la conception du système
Tout cela semble avoir pour but d'éviter un «modèle d'analyse» distinct qui se dissocie de la mise en œuvre réelle du système.
D'après ce que je comprends du livre, il dit que ce «modèle d'analyse» peut finir par être conçu sans tenir compte de l'implémentation logicielle. Une fois que les développeurs essaient de mettre en œuvre le modèle compris par les entreprises, ils forment leurs propres abstractions par nécessité, ce qui crée un mur dans la communication et la compréhension.
Dans l'autre sens, les développeurs introduisant trop de problèmes techniques dans le modèle de domaine peuvent également provoquer cette fracture.
Ainsi, vous pourriez considérer que pratiquer la séparation des préoccupations telles que la persistance peut aider à se prémunir contre ces modèles de conception et d'analyse divergents. S'il s'avère nécessaire d'introduire des éléments comme la persistance dans le modèle, c'est un signal d'alarme. Peut-être que le modèle n'est pas pratique à mettre en œuvre.
Citant:
"Le modèle unique réduit les risques d'erreur, car la conception est désormais une conséquence directe du modèle soigneusement étudié. La conception, et même le code lui-même, a le pouvoir de communication d'un modèle."
La façon dont j'interprète cela, si vous vous retrouvez avec plus de lignes de code traitant de choses comme l'accès à la base de données, vous perdez cette capacité de communication.
Si le besoin d'accéder à une base de données est pour des choses comme la vérification de l'unicité, jetez un œil à:
Udi Dahan: les plus grosses erreurs commises par les équipes lors de l'application de DDD
http://gojko.net/2010/06/11/udi-dahan-the-biggest-mistakes-teams-make-when-applying-ddd/
sous "Toutes les règles ne sont pas égales"
et
Utilisation du modèle de modèle de domaine
http://msdn.microsoft.com/en-us/magazine/ee236415.aspx#id0400119
sous «Scénarios pour ne pas utiliser le modèle de domaine», qui aborde le même sujet.
Comment séparer l'accès aux données
Chargement de données via une interface
La "couche d'accès aux données" a été extraite via une interface que vous appelez pour récupérer les données requises:
var orderLines = OrderRepository.GetOrderLines(orderId);
foreach (var line in orderLines)
{
total += line.Price;
}
Avantages: L'interface sépare le code de plomberie «d'accès aux données», vous permettant ainsi d'écrire des tests. L'accès aux données peut être géré au cas par cas, ce qui permet de meilleures performances qu'une stratégie générique.
Inconvénients: le code d'appel doit supposer ce qui a été chargé et ce qui ne l'est pas.
Dites que GetOrderLines renvoie des objets OrderLine avec une propriété ProductInfo nulle pour des raisons de performances. Le développeur doit avoir une connaissance approfondie du code derrière l'interface.
J'ai essayé cette méthode sur de vrais systèmes. Vous finissez par changer la portée de ce qui est chargé tout le temps pour tenter de résoudre les problèmes de performances. Vous finissez par jeter un œil derrière l'interface pour regarder le code d'accès aux données pour voir ce qui est et n'est pas en cours de chargement.
Désormais, la séparation des préoccupations devrait permettre au développeur de se concentrer sur un seul aspect du code à la fois, autant que possible. La technique d'interface supprime le COMMENT ces données sont chargées, mais pas COMBIEN de données sont chargées, QUAND elles sont chargées et O elles sont chargées.
Conclusion: séparation assez faible!
Chargement paresseux
Les données sont chargées à la demande. Les appels pour charger des données sont masqués dans le graphique d'objet lui-même, où l'accès à une propriété peut entraîner l'exécution d'une requête SQL avant de renvoyer le résultat.
foreach (var line in order.OrderLines)
{
total += line.Price;
}
Avantages: Le «QUAND, O et COMMENT» de l'accès aux données est caché au développeur qui se concentre sur la logique du domaine. Il n'y a pas de code dans l'agrégat qui traite du chargement des données. La quantité de données chargées peut être la quantité exacte requise par le code.
Inconvénients: lorsque vous rencontrez un problème de performances, il est difficile de le résoudre lorsque vous disposez d'une solution générique «taille unique». Le chargement différé peut réduire les performances globales et la mise en œuvre du chargement différé peut être délicate.
Interface de rôle / récupération impatiente
Chaque cas d'utilisation est rendu explicite via une interface de rôle implémentée par la classe d'agrégat, permettant de gérer les stratégies de chargement de données par cas d'utilisation.
La stratégie de récupération peut ressembler à ceci:
public class BillOrderFetchingStrategy : ILoadDataFor<IBillOrder, Order>
{
Order Load(string aggregateId)
{
var order = new Order();
order.Data = GetOrderLinesWithPrice(aggregateId);
return order;
}
}
Ensuite, votre agrégat peut ressembler à:
public class Order : IBillOrder
{
void BillOrder(BillOrderCommand command)
{
foreach (var line in this.Data.OrderLines)
{
total += line.Price;
}
etc...
}
}
BillOrderFetchingStrategy est utilisé pour créer l'agrégat, puis l'agrégat fait son travail.
Avantages: permet un code personnalisé par cas d'utilisation, permettant des performances optimales. Est conforme au principe de séparation des interfaces . Aucune exigence de code complexe. Les tests unitaires d'agrégats n'ont pas à imiter la stratégie de chargement. Une stratégie de chargement générique peut être utilisée dans la majorité des cas (par exemple, une stratégie de "chargement tout") et des stratégies de chargement spéciales peuvent être mises en œuvre si nécessaire.
Inconvénients: le développeur doit encore ajuster / revoir la stratégie de récupération après avoir changé le code de domaine.
Avec l'approche de la stratégie de récupération, vous pouvez toujours changer le code de récupération personnalisé pour une modification des règles métier. Ce n'est pas une séparation parfaite des préoccupations mais finira par être plus facile à entretenir et est meilleure que la première option. La stratégie de récupération encapsule les données HOW, WHEN et WHERE. Il a une meilleure séparation des préoccupations, sans perdre en flexibilité comme l'approche de chargement paresseux.