LuccaSA / RestDrivenDomain

8 stars 1 forks source link

RDD v2.2 - #1 Cache HTTP #95

Open nfaugout-lucca opened 6 years ago

nfaugout-lucca commented 6 years ago

Si on veut utiliser le cache HTTP, il faut que nos API renvoie des entités sans enfant, uniquement avec des FK vers les entités liées.

Techniquement, y'a rien à changer dans le Domain, càd qu'il doit continuer à travailler sur des grappes d'entités complètes. C'est dans la couche Web que, même si on a les enfants sous la main, on coupe le lien au moment de la sérialisation en ne renvoyant que les (id, name, url) de ces sous objets.

Du coup, on peut très bien supporter les 2 approches dans la même version de RDD, càd avoir 2 sérialieurs :

Le fait de supporter les 2 et de gérer ça au niveau Web permet de ne pas remettre massivement en cause RDD.Domain, et donc finalement de pouvoir changer d'avis, si jamais un premier POC sur un projet cobaye s'avère catastrophique.

@Poltuu d'après tes remarques dans l'Issue principale, j'ai l'impression que tu préconises de ne jamais charger de sous entités même dans le Domain, tu confirmes ? Pour ma part je pense qu'on ne devrait gérer ça qu'au niveau de la couche Web, car ça nous permet de continuer à travailler sur des grappes d'objets complets au niveau Domain.

Concernant les "includes", ils sont gérés au niveau des Repositories (Infra), et la différence avec Lucca, c'est qu'ils ne sont plus contextuels, càd qu'il ne faut plus faire des includes en fonction de ce que le demandeur à mis dans les Fields, mais bien faire des includes systématiques qui permet de ramener au Domain un objet toujours complet, avec toutes ses dépendances.

On a vu que c'était lourd de faire des includes systématique dans le monolithe car plus on ajoute de responsabilité sur les entités racines, plus on leur rattache une grosse grappe de données. La "bonne" solution à ce pb n'est pas d'arrêter les includes, mais plutôt de découper une application monolithique en sous applications (ou bounded contexts), ce qui permet de n'avoir qu'une partie de la grappe pour un même concpet, selon le BC dans lequel il se trouve.

Poltuu commented 6 years ago

Je me suis peut-être mal exprimé; j'avais compris qu'on abandonnait la possibilité de charger dynamiquement des sous-entités, les objets exposés devenant moins dynamiques et plus liés à leur contexte, càd avec seules les propriétés correspondant à leur usages dans leur boundedContext. Par exemple, pour un objet à valider, on pourrait trouver la propriété:

{
...
   validator : { id : 3, displayName: "lulu", mail: "mail@lol.com"}
}

avec validatorportant le type "Validator" ne portant QUE les propriétés ayant du sens dans le contexte dans lequel est utilisé l'objet parent (le boundedContext en fait), et toujours chargé avec l'entité. Cela avait plusieurs avantages:

Finalement, il ne fallait pas voir ces propriétés comme des includes automatiques, mais comme des propriétés directement extraites de la vue SQL, donc rapatriées de manière performante (potentiellement)

Donc pour répondre à ta question, je ne préconise pas de ne jamais charger de sous-objets, je suggères de n'avoir qu'un seul format de retour du SQL des objets; quand on demande les objets en base, ils reviennent toujours complets.

nfaugout-lucca commented 6 years ago

Il y a 2 points :

Deux possibilités pour gérer ce dernier point :

Perso je suis pour cette dernière option, qui nous permet de faire un POC agressif sur le cache HTTP.

La "bonne" nouvelle, c'est qu'on n'a pas besoin de faire d'évo à RDD pour tester ça.

En effet, on peut tout à fait développer une appli (genre LuccaFaces) en s'interdisant depuis le front de demander autre chose que (id, name, url) sur les sous ressources. Côté back mettre en place la gestion du cache (TTL, ETag & co sur les entités), et valider le POC.

Et si ça marche, on fait une évo à RDD v2.2 pour gérer en natif ce genre d'approche.

Concernant l'approche BC / redéfinition des concepts, comme ce que tu proposes avec Validator, ça n'est pas incompatible avec une approche radicale au niveau cache HTTP. En effet, au niveau Domain, on peut très bien avoir une richesse des objets, avec des sous objets complets, simplement au moment de la sérialisation, on les "coupe" à (id, name, url). C'est pour ça que je voulais gérer ça au niveau Web.

Je pense à une alternative qui ne nécessite aucune adaptation au niveau sérialisation, et qui consiste à utiliser des interfaces, des implémentations explicites, et de jouer sur le internal/public qu'on a déjà pour indiquer à Web les props qu'on veut sérialiser ou non. Voici ce que ça donnerait avec ton exemple :

IEntityWithValidator qui impose une prop IValidator qui n'a que (Id, Name, Url), et qui sera public au niveau de ton objet Un sous objet internal Validator Validator { get; set } pour l'utilisation dans le Domain.

Ainsi l'objet aurait 2 props :

internal Validator Validator { get; set } public IValidator IEntityWithValidator.Validator { get { return Validator; } }

Perso je préfère gérer le truc au niveau Web/Sérialization pour éviter d'ajouter du "bruit" au niveau du Domain, mais c'est la même idée.

GMouron commented 6 years ago

Attention avec la 2ème solution. Il y a de gros risques de créer des "chatty apis" :

nfaugout-lucca commented 6 years ago

Oui c'est exactement ce qu'on veut faire ici 😄

La différence, c'est qu'on pense que le cache HTTP va régler tous les pb évoqués dans ces 3 posts.

Peut-être qu'on se trompe, et c'est pour ça qu'on va le faire sur un POC, "pour voir", et on reviendra peut-être sur des réponses partielles sans gestion de cache, ou avec une gestion différente.

Mais si on ne teste pas, on ne saura pas ;)

En outre, même si notre back end REST expose des "chatty API", si on voit que c'est lourd, on pourra abattre une dernière carte qui consiste à mettre un back end GrapQL entre le client et le back end REST, qui aura pour job de reconstituer des réponses aggrégées customisées en fonction du front, tout en s'appuyant sur des API REST chatty derrière.

Donc j'ai bon espoir qu'on se mette d'accord pour tester ce nouveau terrain de jeu.

GMouron commented 6 years ago

Bah pour moi la solution 2 ne résout pas ce problème d'un point de vue "client". Seulement du point de vue "ressources serveur". Ça veut pas du tout dire que je suis contre le cache http, bien au contraire. Mais la solution "on référence tout par id,name,url" me semble être un peu la solution de facilité pour nous, mais pas trop pour les clients consommateurs 😉

nfaugout-lucca commented 6 years ago

Tu marques un point, car il faut penser aux intégrations et pas seulement à nos applis front.

On a 3 types de consommateurs de nos API :