Meilleures pratiques pour la sérialisation des agrégats DDD


23

Selon le domaine DDD, la logique ne doit pas être polluée par des problèmes techniques tels que la sérialisation, le mappage relationnel-objet, etc.

Alors, comment sérialiser ou mapper l'état des agrégats sans l'exposer publiquement via des getters et setters? J'ai vu de nombreux exemples, par exemple, d'implémentations de référentiel, mais pratiquement tous s'appuyaient sur des accesseurs publics sur les entités et les objets de valeur pour le mappage.

Nous pourrions utiliser la réflexion pour éviter les accesseurs publics, mais l'OMI, ces objets de domaine dépendraient toujours implicitement du problème de sérialisation. Par exemple, vous ne pouviez pas renommer ou supprimer un champ privé sans modifier votre configuration de sérialisation / mappage. Vous devez donc considérer la sérialisation où vous devriez plutôt vous concentrer sur la logique du domaine.

Alors, quel est le meilleur compromis à suivre ici? Vivez avec des accesseurs publics, mais évitez de les utiliser pour autre chose que le mappage de code? Ou ai-je juste raté quelque chose d'évident?

Je suis explicitement intéressé à sérialiser l'état des objets du domaine DDD (agrégats composés d'entités et d'objets de valeur). Il ne s'agit PAS de sérialisation dans des scénarios de script général ou de transcation où les services sans état fonctionnent sur de simples objets de conteneur de données.

Réponses:


12

Sortes d'objets

Aux fins de notre discussion, séparons nos objets en trois types différents:

Logique du domaine d'activité

Ce sont les objets qui font le travail. Ils transfèrent de l'argent d'un compte courant à un autre, exécutent les commandes et toutes les autres actions que nous attendons des logiciels d'entreprise.

Les objets logiques de domaine ne nécessitent normalement pas d'accesseurs (getters et setters). Au lieu de cela, vous créez l'objet en lui passant des dépendances via un constructeur, puis vous manipulez l'objet à l'aide de méthodes (dites, ne demandez pas).

Objets de transfert de données

Les objets de transfert de données sont à l'état pur; ils ne contiennent aucune logique métier. Ils auront toujours des accesseurs. Ils peuvent ou non avoir des setters, selon que vous les écrivez de manière immuable ou non . Vous définirez vos champs dans le constructeur et leurs valeurs ne changeront pas pendant la durée de vie de l'objet, ou vos accesseurs seront en lecture / écriture. En pratique, ces objets sont généralement modifiables, de sorte qu'un utilisateur peut les modifier.

Afficher les objets du modèle

Les objets du modèle de vue contiennent une représentation de données affichable / modifiable. Ils peuvent contenir une logique métier, généralement limitée à la validation des données. Un exemple d'un objet View Model peut être un InvoiceViewModel, contenant un objet Customer, un objet En-tête de facture et des éléments de ligne de facture. Les objets View Model contiennent toujours des accesseurs.

Ainsi, le seul type d'objet qui sera "pur" dans le sens où il ne contient pas d'accesseurs de champ sera l'objet Logique de domaine. La sérialisation d'un tel objet enregistre son "état de calcul" actuel, de sorte qu'il peut être récupéré plus tard pour terminer le traitement. Les modèles de vue et les DTO peuvent être librement sérialisés, mais dans la pratique, leurs données sont normalement enregistrées dans une base de données.

Sérialisation, dépendances et couplage

S'il est vrai que la sérialisation crée des dépendances, dans le sens où vous devez désérialiser vers un objet compatible, il ne s'ensuit pas nécessairement que vous devez changer votre configuration de sérialisation. De bons mécanismes de sérialisation sont d'usage général; ils ne se soucient pas si vous changez le nom d'une propriété ou d'un membre, tant qu'il peut toujours mapper des valeurs aux membres. En pratique, cela signifie uniquement que vous devez re-sérialiser l'instance d'objet pour rendre la représentation de sérialisation (xml, json, peu importe) compatible avec votre nouvel objet; aucune modification de configuration du sérialiseur ne devrait être nécessaire.

Il est vrai que les objets ne doivent pas se préoccuper de la façon dont ils sont sérialisés. Vous avez déjà décrit une manière de dissocier ces préoccupations des classes de domaine: la réflexion. Mais le sérialiseur doit se préoccuper de la façon dont il sérialise et désérialise les objets; c'est, après tout, sa fonction. La façon dont vous gardez vos objets découplés de votre processus de sérialisation est de faire de la sérialisation une fonction polyvalente , capable de fonctionner sur tous les types d'objets.

Une des choses qui rend les gens confus, c'est que le découplage doit se produire dans les deux sens. Ce ne est pas; il ne doit fonctionner que dans une seule direction. En pratique, vous ne pouvez jamais découpler complètement; il y a toujours un couplage. Le but du couplage lâche est de faciliter la maintenance du code, et non de supprimer toutes les dépendances.


Je partage votre avis sur le découplage. Le sérialiseur dépend de l'objet de domaine et c'est OK. Mais pas l'inverse. Je ne suis cependant pas d'accord avec votre point de vue sur les accesseurs publics sur les objets de domaine. En pratique, ils en ont souvent, oui. Mais OMI, il serait préférable d'implémenter une logique de domaine dans une conception propre orientée objet: dites, ne demandez pas . Mais vous avez toujours besoin d'accesseurs à des fins de cartographie (ORM, sérialisation, GUI ...). Et c'est ce que j'aimerais éviter, si possible.
EagleBeak

Comment prévoyez-vous d'accéder à vos champs, si vous n'avez pas d'accesseurs?
Robert Harvey

En fait, je ne me réfère à aucun des trois types d'objets que vous décrivez, mais aux "agrégats" dans la terminologie DDD et leurs sous-objets (entités, objets de valeur). Je me rends compte maintenant que ma question n'était pas assez explicite à ce sujet. Désolé! Veuillez voir ma modification ci-dessus.
EagleBeak

1
Il s'agit essentiellement d'un problème non résolu - vous ne pouvez pas avoir l'encapsulation, le découplage et la sérialisation \ encodage en même temps exposer le DTO, est une façon de parvenir à un compromis. Il existe cependant des moyens beaucoup moins intrusifs: yegor256.com/2016/07/06/data-transfer-object.html
Basilevs

1
Cela supprime l'encapsulation, n'importe qui peut implémenter ou utiliser la classe friend pour lire les éléments internes de l'objet.
Basilevs

-1

Le but sous-jacent de la sérialisation est de garantir que les données produites par un système peuvent être consommées par un ou plusieurs systèmes compatibles.

L'approche la plus simple et la plus robuste de la sérialisation consiste à traduire les données dans un format de type agnostique qui maintient la structure dans un format simple et facile à consommer. Par exemple, les formats de sérialisation les plus répandus (c'est-à-dire JSON, XML) utilisent un format texte bien défini. Le texte est simple à produire, à transmettre et à consommer.

Il y a 2 raisons pour lesquelles l'utilisation de l'un de ces formats peut ne pas être idéale.

  1. Efficacité

    Il y a un coût inhérent à la traduction de toutes les données en leurs équivalents textuels. Les types de données n'existeraient pas si le texte était le moyen le plus efficace d'exprimer toutes les différentes formes de données. De plus, la structure de ces formats n'est pas idéale pour récupérer des sous-ensembles de données de manière asynchrone ou partielle.

    Par exemple, XML et JSON supposent que les données utilisées seront écrites et lues du début à la fin. Pour le traitement de très grands ensembles de données où la mémoire est rare, le système consommant les données peut nécessiter la capacité de traiter les données en plusieurs parties. Dans ce cas, une implémentation spéciale de sérialisation / désérialisation peut être nécessaire pour gérer les données.

  2. Précision

    Le casting requis pour sérialiser / désérialiser les données de leur type prévu en type agnostique de données entraîne une perte de précision.

On pourrait soutenir que produire une représentation binaire des objets et des données est clairement la solution la plus efficace et la plus précise. L'inconvénient majeur est que la mise en œuvre de tous les systèmes qui consomment et produisent des données doivent rester compatibles. C'est une simple contrainte en théorie mais c'est un cauchemar à maintenir dans la pratique car les systèmes de production ont tendance à changer / évoluer avec le temps.

Ceci étant dit. Le découplage de la sérialisation / désérialisation des détails spécifiques au domaine a du sens en règle générale, car les formats à usage général sont plus robustes, mieux pris en charge sur divers systèmes et nécessitent peu ou pas de surcharge de maintenance accrue à utiliser.


Désolé, mais cela ne répond pas à ma question. Il s'agit de découpler les objets de domaine de la sérialisation, pas des raisons de la sérialisation ou des avantages et inconvénients de divers formats. Comment sérialiser des objets de domaine sans exposer publiquement leur état privé?
EagleBeak

@EagleBeak Oh, je ne savais pas que votre préoccupation concernait spécifiquement la gestion des membres privés. Dans votre cas, vous pouvez sérialiser en binaire (en supposant que le système de réception suit les mêmes règles / structure que celles sous lesquelles les objets de domaine ont été créés) ou écrire une logique qui extrait uniquement les données publiques avant la sérialisation.
Evan Plaice

Je pense que l'hypothèse `` habituelle '' est que les données sérialisées dans un format à usage général (ex xml, json) seront publiques et que ce privilège est contrôlé via l'API via des ACL ou tout autre équivalent. La sérialisation / désérialisation à usage général s'inscrit davantage dans le découplage des données de la logique métier d'un système à l'autre.
Evan Plaice

Je suis d'accord sur le fait que les accesseurs publics sont généralement supposés sur les objets à sérialiser. Mais je voudrais quand même en savoir plus sur la façon dont cela se rapporte à DDD et sa forte concentration sur l'encapsulation de la logique du domaine. Tous les praticiens DDD exposent-ils simplement l'état du modèle de domaine via des accesseurs publics pour la sérialisation (et ne le mentionnent jamais dans leurs exemples)? J'en doute. S'il vous plaît, ne vous méprenez pas. J'apprécie beaucoup votre contribution. C'est juste que je m'intéresse à un aspect différent. (Jusqu'à présent, je ne pense pas que ma question soit trop vague, mais la réponse de Robert Harvey et la vôtre m'ont
amené à y
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.