Open nfaugout-lucca opened 6 years ago
J'ai du mal à comprendre où sont les ValueObjects, dans le domain ?
Ce sont des DTO avec le mapping fait dans le constructeur de la classe cible en fait ? 😁
Ouais exactement ! C'est ce que je me suis dit en l'écrivant ! La grosse différence avec un DTO, c'est que c'est embarqué nativement dans l'OOP là où avec les DTO tu peux faire ce que tu veux sans que ça ait un impact sur ta façon d'architecturer ton Domain ou de l'exposer.
Là on a une contrainte forte qui te pousse à ne pas faire "n'importe quoi", càd que si tu te retrouves avec 10 constructeurs, c'est peut-être qu'il y a un pb.
C'est intéressant, mais comment Rdd peut-il imposer ces normes ? il faut alors rajouter un type "DTO" dans toute la chaine WebController -> Appcontroller -> Collection, mais ce n'est pas suffisant en réalité. Egalement, on ne peut pas imposer de contrainte de type sur les paramètres du constructeur, donc là on est coincé (il faut jouer avec l'instanciator)
Il y a aussi un problème c'est que dans ton exemple, c'est joli, on passe un patronyme et ça ressort un user, mais dans la réalité, il faudra 80% des champs d'un user, donc on se retrouvera plutôt avec un "espèce de user" dans le constructeur. Et comme les champs du domain sont déjà bien nommés, ce sera vraiment très proche d'une copie, càd un objet DTO passe-plat quasi en opposition totale avec l'actuel RDD, qui pousse un seul objet de haut en bas
Enfin pour le constructeur, en effet EF ne supporte pas un objet en entrée, donc il faudrait toujours un constructeur vide, ou paramétré avec les props de l'objet en question https://docs.microsoft.com/en-us/ef/core/modeling/constructors
Donc pas mal de souci derrière cette idée, à laquelle j'adhère partiellement ceci dit.
Moi je me pose la question de la philosophie et des principes sur lesquels on s'appuie pour coder RDD, notamment cette partie écriture. Jusqu'à présent, RDD a toujours été plus "REST" que "DDD", puisqu'en gros RDD c'est un api REST, avec des couches orientés Domain. Et dans une logique REST pure, RDD tape plutôt juste, puisque notamment, on POST des entités telles que ce qu'on espère retrouver en GET.
Moi je pense qu'on pourrait peut-être se détourner de cette logique, et orienter ou au moins permettre plus de DDD, avec notamment du CQRS. C'est au fond ce que tu propose ici, faire des POST/PUT avec des objets différents que ce que l'on reçoit en GET. Si on se tourne vers / permet du CQRS, on retrouve une grande partie de ce que tu proposes dans ce post, mais par contre, ça demande des modifications sur d'autres sujets, puisque dans cette logique:
En conclusion:
Le coup du constructeur n'est pas techniquement faisable d'un point de vue archi : les ValueObjects que tu souhaites utiliser n'ont vocation a exister que dans la couche web, et pas dans la couche Domain. Et les constructeurs des objets du Domain ne peuvent pas connaitre de type de la couche web. Donc pour moi c'est pas bon.
Comme évoqué, the way to go is obvious, c'est le CQRS, et c'est aujourd'hui tellement lié au DDD dans la littérature qu'on aurait tords de s'y refuser. (Je promet d'attendre un peu pour l'event-sourcing 😸)
@alexcarpe la discussion dont on parlait ce matin pour ton use case au niveau de la création des Reviews.
Suite à une discussion avec Raph, voici une proposition de changement de paradigme pour l'instanciation des entités et leur validation.
Constructeurs des entités
On s'intéresse d'abord (et toujours) au Domain. L'idée ici c'est de renforcer les contraintes, càd qu'on ne puisse plus créer une entité n'importe comment.
La conséquence c'est que la plupart des propriétés des entités ont leur
set
qui devientprivate
, de sorte qu'une entité maîtrise ses changements d'état, qui ne pourront alors venir QUE de ses constructeurs ou de méthodes explicites qui changent telle ou telle propriété.On vire le constructeur vide (ou en tout cas sa philosophie), et on crée autant de constructeurs qu'on veut de façon d'instancier une entité.
Pour respecter le principe du typage fort, on utilise, pour chaque constructeur un valueObject qui représente les paramètres qu'on aurait voulu y mettre : un seul paramètre par constructeur donc.
La validation lors de l'instanciation est donc déportée sur ces valueObjects qui peuvent alors avoir de la data annotation et une méthode de validation. Il sera alors impossible de les instancier depuis la couche web ou ailleurs dans un état invalide.
Voici un exemple :
Depuis la couche Web, cela se traduit par des Post explicites, comme suit :
NB : Si EF est capable de setter les propriétés sans passer par les constructeurs ou s'il est compatible avec ces constructeurs et qu'on peut lui indiquer le mapping entre les valueObjects et les colonnes dans les tables (à l'instar des ComplexType dans la version précédente d'EF), alors ça ne posera pas de problème en lecture.
Validation
Ici on voit que la validation est nettement simplifiée :