Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nouveau paradigme de création/validation des entités #259

Open
nfaugout-lucca opened this issue Oct 25, 2018 · 5 comments
Open

Nouveau paradigme de création/validation des entités #259

nfaugout-lucca opened this issue Oct 25, 2018 · 5 comments

Comments

@nfaugout-lucca
Copy link
Contributor

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 devient private, 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 :

public class User {
  public string LastName { get; }
  public string FirstName { get; }
  public User(Patronym patronym) {
    LastName = patronym.LastName;
    FirstName = patronym.FirstName;
  }
}

Depuis la couche Web, cela se traduit par des Post explicites, comme suit :

public class UsersController {
  [HttpPost]
  public async Task<IActionResult> PostAsync(Patronym patronym)
  {
    var user = new User(patronym);
    await AppController.CreateAsync(user);
    ...
  }

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 :

  • par le fait que les valueObjects sont directement désérialisés par AspNet, et donc si invalides ça plante direct
  • par le fait que les entités sont impossible à instancier autrement que via des formes valides de valueOjects
  • on peut néanmoins ajouter une méthode de validation, appelée par le controller applicatif sur l'entitié juste avant d'appeler la collection, à voir..
@ThibautRappet
Copy link
Contributor

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 ? 😁

@nfaugout-lucca
Copy link
Contributor Author

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.

@Poltuu
Copy link
Contributor

Poltuu commented Oct 25, 2018

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:

  • je pense que l'idée proposée est bonne
  • la réaliser n'est pas possible sur la plupart des objets aujourd’hui utilisés
  • la réaliser demande de développer une partie CQRS dans RDD toute nouvelle, ce qui est une direction enviable selon moi

@rducom
Copy link
Contributor

rducom commented Oct 26, 2018

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 😸)

@nfaugout-lucca
Copy link
Contributor Author

@alexcarpe la discussion dont on parlait ce matin pour ton use case au niveau de la création des Reviews.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants