DDD et objets de valeur. Les objets de valeur mutables sont-ils un bon candidat pour Non Aggr. Entité racine?

9

Voici un petit problème

Avoir une entité, avec un objet valeur. Pas de problème. Je remplace un objet valeur par un nouveau, puis nhibernate insère la nouvelle valeur et rend orphelin l'ancienne, puis la supprime. D'accord, c'est un problème.

L'assuré est mon entité dans mon domaine. Il possède une collection d'adresses (objets de valeur). L'une des adresses est MailingAddress. Lorsque nous voulons mettre à jour l'adresse postale, disons que le code postal était incorrect, conformément à la doctrine de M. Evans, nous devons remplacer l'ancien objet par un nouveau car il est immuable (un objet de valeur, n'est-ce pas?).

Mais nous ne voulons pas supprimer la ligne, car le PK de cette adresse est un FK dans une table MailingHistory. Donc, suivant la doctrine de M. Evans, nous sommes à peu près foutus ici. À moins que je ne crée mes adresses, je n'ai donc pas besoin de le "remplacer" et de simplement mettre à jour son code postal, comme au bon vieux temps.

Que me suggéreriez-vous dans ce cas? À mon avis, les ValueObjects ne sont utiles que lorsque vous souhaitez encapsuler un groupe de colonnes de table de base de données (composant dans nhibernate). Tout ce qui a un identifiant de persistance dans la base de données, il vaut mieux en faire une entité (pas nécessairement une racine agrégée) afin que vous puissiez mettre à jour ses membres sans recréer le graphique d'objet entier, surtout s'il s'agit d'un objet profondément imbriqué.

Êtes-vous d'accord? Est-il permis à M. Evans d'avoir un objet de valeur mutable? Ou un objet de valeur mutable est-il candidat à une entité?

Merci

Pepito Fernandez
la source
2
Existe-t-il quelque chose comme "objet de valeur mutable"? J'ai toujours eu l'impression que les objets de valeur sont immuables.
herby
@herby Je suppose que vous pourriez avoir un objet mutable représentant un objet de valeur DDD dans le code, mais vous devriez considérer qu'une fois que vous avez muté l'objet, il ne fait plus référence au même objet de valeur DDD logique mais à un nouveau. Cela peut être souhaitable, mais c'est une recette pour créer de la confusion en créant des objets de valeur immuables dans le code est une convention intelligente.
MattDavey

Réponses:

8

Tout ce qui a une identité doit être une entité, et tout ce qui n'a pas d'identité est une simple valeur, donc un objet de valeur.

Pour citer Martin Fowler (qui à son tour qoutes Eric Evans)

  • Entité: objets qui ont une identité distincte qui traverse le temps et différentes représentations. Vous entendez également ces objets appelés «objets de référence».
  • Objet de valeur: les objets qui comptent n'ont que la combinaison de leurs attributs.

Raison de faire de votre adresse un objet de valeur:

Si votre adresse est modifiable, vous finirez probablement par visser votre historique de diffusion. Par exemple, si vous expédiez des articles à un client, vous ne pouvez pas être sûr de l'adresse à laquelle vous avez réellement expédié quelque chose par le passé si l'adresse à laquelle votre table MailingHistory fait référence a été modifiée.

L'entrée MailingHistory Nous avons expédié A764 à l'adresse 657 pourrait signifier Nous avons expédié l'article A764 à Boston hier et Nous avons expédié l'article A764 à New York demain.

Si l'adresse postale doit être modifiée, il n'est pas nécessaire de supprimer l'ancienne. Gardez-le et marquez-le comme inactif , et le nouveau comme actif .


Bien sûr, vous pouvez traiter votre adresse comme une entité, mais uniquement lors de la mise à jour, cela ne changera pas le lieu réel auquel l'adresse fait référence, permettant ainsi uniquement la correction des fautes de frappe.

Si vous êtes sûr de pouvoir le garantir, il serait possible d'utiliser une entité.


Mais la meilleure solution à mon humble avis est de ne pas référencer une entité d'adresse dans votre historique de diffusion, mais plutôt d'enregistrer l'adresse spécifique directement dans votre table d'historique de diffusion (en copiant essentiellement les données de l'adresse).

De cette façon, vous savez toujours où vous avez expédié vos articles (ou tout ce que vous envoyez), et puisque vous utiliseriez une entité mutable, votre table d'adresses ne sera pas encombrée.

J'ai travaillé avec / sur plusieurs systèmes ERP, et presque tous ont utilisé cette approche.

Vous aurez une certaine redondance dans votre base de données, mais c'est la manière la plus pragmatique à mon humble avis.

la paresse
la source
C'est probablement la solution la plus exempte de maux de tête. Ce n'est que si vous vous attendez à ce que les futurs canaux de communication nécessitent des colonnes supplémentaires et que votre base de données soit trop volumineuse qu'il ALTERsoit nécessaire d'utiliser des entités dans des tables distinctes. Cela, à son tour, nécessite des stratégies telles que «toujours joindre la dernière adresse / téléphone / e-mail» dans vos SELECTrequêtes, qui sont difficiles à maintenir maintenables et efficaces. Restez simple, si possible.
Timo
@Timo "toujours rejoindre la dernière adresse / téléphone / e-mail" n'est pas difficile si vous dénormalisez un peu vos données en ajoutant simplement un active-flag. Bien sûr, vous devez vous assurer de toujours utiliser and active = truedans vos jointures, de maintenir le drapeau à jour et d'ajouter une contrefaçon à votre table afin que, par exemple, un seul e-mail pour chaque client puisse avoir ce drapeau défini sur true.
paresse
Cela pose le problème de la désactivation de la précédente. Si vous avez remplacé l'objet d'adresse "actuel" de votre instance dans le code et que vous accédez à votre code d'accès aux données, il ne saura pas (1) s'il y en a un nouveau, ni (2) quel est l'ancien potentiel l'un l'était. Ainsi, chaque opération de sauvegarde devra faire quelque chose de compliqué comme "tout d'abord aller et désactiver toutes les adresses associées dans la base de données", puis enregistrer celle en cours avec active=true. Ce n'est pas ce que j'appellerais simple, c'est exactement pourquoi j'aime votre solution.
Timo
2

Je vois 2 choses:

  1. Est-il acceptable que le changement de code postal affecte un enregistrement d'historique? Je pense qu'il serait logique que l'enregistrement historique pointe vers l'ancienne adresse inchangée, vous savez donc que vous l'envoyez à une mauvaise adresse.

  2. Au moment où MailingHistory a FK sur l'adresse, l'adresse a cessé d'être un objet de valeur et est devenue une entité. Les objets de valeur n'ont pas d'identité, ce qui permet à d'autres entités de référencer cette identité. Vous pouvez avoir des adresses dans une table unique avec d'autres tables pointant dessus, mais le seul effet est d'économiser de l'espace. Du point de vue du domaine, si deux entités ont en référence le même type d'objet de valeur, elles ne partagent aucun type d'informations.

Euphorique
la source
2

IMO l'objet adresse est une entité de votre domaine. Il est partagé par plusieurs entités, possède sa propre identité et est unique à travers le système.

Evans dit:

Un objet défini principalement par son identité est appelé une entité.

margabit
la source
Les identités de domaine, à ma connaissance, n'ont rien à voir avec l'identité de persistance. Selon le livre de M. Evan.
Pepito Fernandez
Tu as raison. Je modifie ma réponse. Ce que je veux dire, c'est que l'adresse de l'objet est importante dans ce domaine spécifique, elle est unique. IMO la clé étrangère et la clé primaire est un signe qu'il s'agit en fait d'un objet unique dans tout le domaine, donc il a une identité.
margabit
1
"l'objet d'adresse ... a sa propre identité" - quel attribut d'une adresse l'identifie de manière unique? Aucun attribut unique d'une adresse n'est unique, mais la combinaison d'attributs sert d'identité. Ceci est la définition même d'un objet de valeur
MattDavey
@MattDavey: c'est une bonne conclusion, mais je suis confus quand Tony dit "nous ne voulons pas supprimer la ligne, car le PK de cette adresse est un FK dans une table MailingHistory". Cela signifie pour moi que l'objet Adresse a également une signification en dehors de l'agrégat «assuré». Ce qui m'indique que l'objet 'Address' ne doit pas être un ValueObject. Qu'est-ce que tu penses?
margabit
Pourrions-nous dire que les objets de valeur seraient invariablement la propriété à part entière (UML) du parent? De plus, un objet de valeur n'aurait aucun sens sans son parent et ne peut pas être partagé entre les parents?
Sudarshan