Les services doivent-ils toujours renvoyer des DTO ou peuvent-ils également renvoyer des modèles de domaine?


175

Je (re) conçois des applications à grande échelle, nous utilisons une architecture multicouche basée sur DDD.

Nous avons MVC avec couche de données (implémentation de référentiels), couche de domaine (définition du modèle de domaine et interfaces - référentiels, services, unité de travail), couche de service (implémentation de services). Jusqu'à présent, nous utilisons des modèles de domaine (principalement des entités) sur toutes les couches, et nous utilisons les DTO uniquement comme modèles de vue (dans le contrôleur, le service renvoie le (s) modèle (s) de domaine et le contrôleur crée le modèle de vue, qui est passé à la vue).

J'ai lu d'innombrables articles sur l'utilisation, la non-utilisation, le mappage et la transmission des DTO. Je comprends qu'il n'y a pas de réponse définitive, mais je ne suis pas sûr que ce soit correct ou non de renvoyer les modèles de domaine des services aux contrôleurs. Si je retourne le modèle de domaine, il n'est toujours jamais passé à la vue, car le contrôleur crée toujours un modèle de vue spécifique à la vue - dans ce cas, cela semble légitime. D'un autre côté, cela ne se sent pas bien lorsque le modèle de domaine quitte la couche métier (couche de service). Parfois, le service doit renvoyer un objet de données qui n'a pas été défini dans le domaine, puis nous devons soit ajouter un nouvel objet au domaine qui n'est pas mappé, soit créer un objet POCO (c'est moche, car certains services renvoient des modèles de domaine, certains renvoyer effectivement les DTO).

La question est la suivante: si nous utilisons strictement des modèles de vue, est-il acceptable de renvoyer les modèles de domaine jusqu'aux contrôleurs, ou devrions-nous toujours utiliser les DTO pour la communication avec la couche de service? Si tel est le cas, est-il possible d'ajuster les modèles de domaine en fonction des besoins des services? (Franchement, je ne pense pas, car les services devraient consommer ce que le domaine a.) Si nous devons nous en tenir strictement aux DTO, devraient-ils être définis dans la couche de service? (Je pense que oui.) Parfois, il est clair que nous devrions utiliser des DTO (par exemple, lorsque le service exécute beaucoup de logique métier et crée de nouveaux objets), parfois il est clair que nous devrions utiliser uniquement des modèles de domaine (par exemple, lorsque le service Membership renvoie un utilisateur anémique ( s) - il semble que cela n'aurait pas beaucoup de sens de créer un DTO identique au modèle de domaine) - mais je préfère la cohérence et les bonnes pratiques.

Article Domain vs DTO vs ViewModel - Comment et quand les utiliser? (et aussi quelques autres articles) est très similaire à mon problème, mais il ne répond pas à cette (ces) question (s). Article Dois-je implémenter des DTO dans un modèle de référentiel avec EF? est également similaire, mais il ne traite pas de DDD.

Avertissement: Je n'ai pas l'intention d'utiliser un modèle de conception uniquement parce qu'il existe et est sophistiqué, d'un autre côté, j'aimerais utiliser de bons modèles et pratiques de conception également parce que cela aide à concevoir l'application dans son ensemble, aide à la séparation des préoccupations, même le fait d'utiliser un modèle particulier n'est pas "nécessaire", du moins pour le moment.

Comme toujours, merci.


28
Pour les gars qui votent pour la clôture - pourriez-vous expliquer pourquoi vous souhaitez fermer cette question en tant qu'opinion?
Robert Goldwein le

20
@Aron "Code Review est un site de questions et réponses permettant de partager le code des projets sur lesquels vous travaillez pour un examen par les pairs." - ma question ne porte pas du tout sur le code, donc ce serait hors sujet; SO: "Concentrez-vous sur des questions sur un problème réel auquel vous avez été confronté. Incluez des détails sur ce que vous avez essayé et ce que vous essayez de faire exactement." - J'ai un problème d'expert spécifique, que j'ai essayé de résoudre. Pourriez-vous s'il vous plaît être plus précis ce qui ne va pas avec cette question, puisque de nombreuses questions ici concernent l'architecture et que de telles questions sont apparemment correctes, afin que je puisse éviter tout autre malentendu?
Robert Goldwein le

7
Merci d'avoir posé cette question. Vous m'avez rendu service et avez rendu ma vie beaucoup plus simple et heureuse, merci.
Loa

9
@RobertGoldwein, ne vous inquiétez pas de la mafia SO Close, votre question est légitime.
hyankov

3
Un grand merci d'avoir posé cette question
salman

Réponses:


177

il ne se sent pas bien lorsque le modèle de domaine quitte la couche métier (couche de service)

Vous donne l'impression de tirer les tripes, n'est-ce pas? Selon Martin Fowler: la couche de service définit les limites de l'application, elle encapsule le domaine. En d'autres termes, il protège le domaine.

Parfois, le service doit renvoyer un objet de données qui n'a pas été défini dans le domaine

Pouvez-vous donner un exemple de cet objet de données?

Si nous devons nous en tenir strictement aux DTO, doivent-ils être définis dans la couche de service?

Oui, car la réponse fait partie de votre couche de service. S'il est défini «ailleurs», alors la couche de service doit faire référence à «ailleurs», ajoutant une nouvelle couche à vos lasagnes.

est-il acceptable de renvoyer les modèles de domaine jusqu'aux contrôleurs, ou devrions-nous toujours utiliser les DTO pour la communication avec la couche de service?

Un DTO est un objet de réponse / demande, cela a du sens si vous l'utilisez pour la communication. Si vous utilisez des modèles de domaine dans votre couche de présentation (MVC-Controllers / View, WebForms, ConsoleApp), alors la couche de présentation est étroitement couplée à votre domaine, toute modification dans le domaine vous oblige à changer vos contrôleurs.

il semble que cela n'aurait pas beaucoup de sens de créer un DTO identique au modèle de domaine)

C'est l'un des inconvénients du DTO pour les nouveaux yeux. À l'heure actuelle, vous pensez à la duplication de code , mais à mesure que votre projet se développe, cela aurait beaucoup plus de sens, en particulier dans un environnement d'équipe où différentes équipes sont affectées à différentes couches.

DTO peut ajouter une complexité supplémentaire à votre application, tout comme vos couches. DTO est une fonctionnalité coûteuse de votre système, ils ne sont pas gratuits.

Pourquoi utiliser un DTO

Cet article présente à la fois l'avantage et l'inconvénient d'utiliser un DTO, http://guntherpopp.blogspot.com/2010/09/to-dto-or-not-to-dto.html

Résumé comme suit:

Quand utiliser

  • Pour les grands projets.
  • La durée de vie du projet est de 10 ans et plus.
  • Application stratégique et critique.
  • Grandes équipes (plus de 5)
  • Les développeurs sont répartis géographiquement.
  • Le domaine et la présentation sont différents.
  • Réduire les échanges de données supplémentaires (l'objectif initial du DTO)

Quand ne pas utiliser

  • Projet de petite à moyenne taille (5 membres maximum)
  • La durée de vie du projet est d'environ 2 ans.
  • Aucune équipe distincte pour l'interface graphique, le backend, etc.

Arguments contre DTO

Arguments avec DTO

  • Sans DTO, la présentation et le domaine sont étroitement liés. (Cela convient aux petits projets.)
  • Stabilité de l'interface / API
  • Peut fournir une optimisation pour la couche de présentation en renvoyant un DTO contenant uniquement les attributs absolument nécessaires. En utilisant linq-projection , vous n'avez pas besoin d'extraire une entité entière.
  • Pour réduire les coûts de développement, utilisez des outils de génération de code

3
Salut, merci pour votre réponse, c'est vraiment un bon résumé pour, et merci aussi pour les liens. Ma phrase "Parfois, le service doit renvoyer un objet de données qui n'a pas été défini dans le domaine" a été mal choisie, cela signifie que le service combine plusieurs DO d'un référentiel (par exemple, des attributs) et produit un POCO en tant que composition de ces attributs (basé sur la logique métier). Encore une fois, merci pour une très belle réponse.
Robert Goldwein

1
La manière dont ces modèles de domaine ou DTO sont renvoyés par votre service est une considération importante en matière de performances. Avec EF, si vous réalisez une requête pour renvoyer une collection concrète de modèles de domaine (avec un .ToArray () ou ToList (), par exemple), vous sélectionnez toutes les colonnes pour remplir les objets réalisés. Si vous projetez le DTO dans la requête à la place, EF est assez intelligent pour sélectionner uniquement les colonnes requises pour remplir votre DTO, ce qui peut être beaucoup moins de données à transférer dans certains cas.
sniffer

10
Vous pouvez cartographier vos objets «à la main». Je sais, des trucs ennuyeux, mais cela prend 2-3 min par modèle et il y a toujours une possibilité d'apporter beaucoup de problèmes lorsque vous utilisez beaucoup de réflexion (AutoMapper etc.)
Razvan Dumitru

1
merci d'avoir répondu si simplement et avec un tel contenu. Vous m'avez rendu service et avez rendu ma vie beaucoup plus simple et heureuse, merci.
Loa

1
Nous avons eu un projet de 10 millions annulé parce qu'il était trop lent ... Pourquoi était-ce lent? Transfert de l'objet DTO partout en utilisant la refelection. Faites attention. Automapper utilise également la réflexion.
RayLoveless

11

Il semble que votre application soit suffisamment grande et complexe car vous avez décidé de passer par l'approche DDD. Ne renvoyez pas vos entités poco ou ce que l'on appelle des entités de domaine et des objets de valeur dans votre couche de service. Si vous voulez faire cela, supprimez votre couche de service car vous n'en avez plus besoin! Les objets de modèle de vue ou de transfert de données doivent vivre dans la couche Service, car ils doivent être mappés aux membres du modèle de domaine et vice versa. Alors pourquoi avez-vous besoin d'un DTO? Dans une application complexe avec de nombreux scénarios, vous devez séparer les préoccupations du domaine et vos vues de présentation, un modèle de domaine peut être divisé en plusieurs DTO et plusieurs modèles de domaine peuvent être réduits en un DTO. Il est donc préférable de créer votre DTO dans une architecture en couches, même si ce serait le même que votre modèle.

Devrions-nous toujours utiliser les DTO pour la communication avec la couche de service? Oui, vous devez renvoyer le DTO par votre couche de service car vous avez parlé à votre référentiel dans la couche de service avec les membres du modèle de domaine et les mapper au DTO et revenir au contrôleur MVC et vice versa.

Est-il acceptable d'ajuster les modèles de domaine en fonction des besoins des services? Un service ne concerne que les méthodes de référentiel et de domaine et les services de domaine, vous devez résoudre l'entreprise de votre domaine en fonction de vos besoins et ce n'est pas la tâche de service de dire au domaine ce qui est nécessaire.

Si nous devons nous en tenir strictement aux DTO, doivent-ils être définis dans la couche de service? Oui, essayez d'avoir DTO ou ViewModel juste en service plus tard, car ils devraient être mappés aux membres du domaine dans la couche de service et ce n'est pas une bonne idée de placer DTO dans les contrôleurs de votre application (essayez d'utiliser le modèle de demande de réponse dans votre couche de service), bravo !


1
Désolé pour ça! vous pouvez le voir ici ehsanghanbari.com/blog/Post/7/…
Ehsan

10

D'après mon expérience, vous devriez faire ce qui est pratique. «Le meilleur design est le design le plus simple qui fonctionne» - Einstein. Avec cela, c'est l'esprit ...

si nous utilisons strictement des modèles de vue, est-il acceptable de renvoyer les modèles de domaine jusqu'aux contrôleurs, ou devrions-nous toujours utiliser les DTO pour la communication avec la couche de service?

Absolument c'est ok! Si vous avez des entités de domaine, des DTO et des modèles de vue, y compris les tables de base de données, tous les champs de l'application sont répétés à 4 endroits. J'ai travaillé sur de grands projets où les entités de domaine et les modèles de vue fonctionnaient très bien. La seule exception à cela est que l'application est distribuée et que la couche de service réside sur un autre serveur, auquel cas les DTO doivent envoyer via le câble pour des raisons de sérialisation.

Si tel est le cas, est-il possible d'ajuster les modèles de domaine en fonction des besoins des services? (Franchement, je ne le pense pas, car les services devraient consommer ce que le domaine a.)

En général, je suis d'accord et je dirais non parce que le modèle de domaine est généralement le reflet de la logique métier et n'est généralement pas façonné par le consommateur de cette logique.

Si nous devons nous en tenir strictement aux DTO, doivent-ils être définis dans la couche de service? (Je le pense.)

Si vous décidez de les utiliser, je serais d'accord et je dirais que la couche Service est l'endroit idéal car elle renvoie les DTO à la fin de la journée.

Bonne chance!


8

Je suis en retard à cette fête, mais c'est une question tellement courante et importante que je me suis senti obligé de répondre.

Par "services", vous entendez la "couche d'application" décrite par Evan's dans le livre bleu ? Je suppose que vous le faites, auquel cas la réponse est qu'ils ne devraient pas renvoyer les DTO. Je suggère de lire le chapitre 4 du livre bleu, intitulé «Isoler le domaine».

Dans ce chapitre, Evans dit ce qui suit à propos des couches:

Partitionnez un programme complexe en couches. Développez une conception au sein de chaque couche qui est cohérente et qui ne dépend que des couches ci-dessous.

Il y a de bonnes raisons pour cela. Si vous utilisez le concept d' ordre partiel comme mesure de la complexité du logiciel, le fait d' avoir une couche dépend d'une couche au-dessus augmente la complexité, ce qui diminue la maintenabilité.

En appliquant cela à votre question, les DTO sont vraiment un adaptateur qui concerne la couche Interface utilisateur / Présentation. N'oubliez pas que la communication à distance / inter-processus est exactement le but d'un DTO (il convient de noter que dans cet article, Fowler fait également valoir que les DTO font partie d'une couche de service, bien qu'il ne parle pas nécessairement le langage DDD).

Si votre couche d'application dépend de ces DTO, cela dépend d'une couche au-dessus d'elle-même et votre complexité augmente. Je peux vous garantir que cela augmentera la difficulté de maintenir votre logiciel.

Par exemple, que se passe-t-il si votre système s'interface avec plusieurs autres systèmes ou types de clients, chacun nécessitant leur propre DTO? Comment savoir quel DTO une méthode de votre service d'application doit renvoyer? Comment résoudriez-vous même ce problème si la langue de votre choix ne permet pas de surcharger une méthode (méthode de service, dans ce cas) basée sur le type de retour? Et même si vous trouvez un moyen, pourquoi violer votre couche d'application pour prendre en charge un problème de couche de présentation?

Concrètement, c'est un pas sur une route qui se terminera par une architecture spaghetti. J'ai vu ce genre de décentralisation et ses résultats dans ma propre expérience.

Là où je travaille actuellement, les services de notre couche d'application renvoient des objets de domaine. Nous ne considérons pas cela comme un problème car la couche Interface (ie UI / Presentation) dépend de la couche Domain, qui se trouve en dessous . En outre, cette dépendance est réduite à un type de dépendance "référence uniquement" car:

a) la couche d'interface ne peut accéder à ces objets de domaine qu'en tant que valeurs de retour en lecture seule obtenues par des appels à la couche d'application

b) les méthodes sur les services de la couche application n'acceptent en entrée que l'entrée "brute" (valeurs de données) ou les paramètres d'objet (pour réduire le nombre de paramètres si nécessaire) définis dans cette couche. Plus précisément, les services d'application n'acceptent jamais les objets de domaine comme entrée.

La couche d'interface utilise des techniques de mappage définies dans la couche d'interface elle-même pour mapper des objets du domaine vers les DTO. Encore une fois, cela permet aux DTO de rester concentrés sur les adaptateurs contrôlés par la couche d'interface.


1
Question rapide. Je suis actuellement en train de déterminer ce qu'il faut retourner de ma couche d'application. Le retour des entités de domaine à partir de la couche d'application ne semble pas correct. Est-ce que je veux vraiment divulguer le domaine vers «l'extérieur»? J'envisageais donc les DTO de la couche application. Mais cela ajoute un autre modèle. Dans votre réponse, vous avez dit que vous renvoyiez les modèles de domaine en tant que «valeurs de retour en lecture seule». Comment tu fais ça? Ie, comment les faites-vous en lecture seule?
Michael Andrews

Je pense que je vais simplement adopter votre position. Les services d'application renvoient des modèles de domaine. Les couches de l'adaptateur de port (REST, présentation, etc.) les traduisent ensuite dans leur propre modèle (modèle de vue ou représentations). L'ajout d'un modèle DTO entre l'application et les adaptateurs de port semble exagéré. Les modèles de domaine de retour adhèrent toujours à DIP, et la logique de domaine reste à l'intérieur du contexte borné (pas nécessairement à l'intérieur de la limite de l'application. Mais cela semble être un bon compromis).
Michael Andrews

@MichaelAndrews, heureux d'entendre que ma réponse a aidé. Re: votre question sur les objets retournés étant en lecture seule, les objets eux-mêmes ne sont pas vraiment en lecture seule (c'est-à-dire immuables). Ce que je veux dire, c'est que cela n'arrive pas dans la pratique (du moins d'après mon expérience). Pour mettre à jour un objet de domaine, la couche d'interface devrait soit a) référencer le référentiel de l'objet de domaine, soit b) rappeler la couche d'application pour mettre à jour l'objet qu'elle vient de recevoir. L'une ou l'autre de ces violations est si évidente aux bonnes pratiques DDD que je trouve qu'elles sont auto-appliquées. N'hésitez pas à voter pour la réponse si vous le souhaitez.
BitMask777

Cette réponse m'est très intuitive pour plusieurs raisons. Tout d'abord, nous pouvons réutiliser la même couche d'application pour plusieurs interfaces utilisateur (API, contrôleurs) et chacune peut transformer le modèle comme bon lui semble. Deuxièmement, si nous devions transformer le modèle en DTO dans App. Couche, cela signifierait que DTO est défini dans App. Layer, ce qui signifie à son tour que DTO fait maintenant partie de notre contexte borné (pas nécessairement de domaine!) - cela semble juste faux.
Robotron

1
J'étais sur le point de vous poser une question de suivi et j'ai vu que vous y aviez déjà répondu: "les services d'application n'acceptent jamais les objets du domaine comme entrée". Je donnerais +1 encore si je le pouvais.
Robotron

5

En retard à la fête, mais je suis confronté exactement au même type d'architecture et je penche vers «uniquement les DTO du service». C'est principalement parce que j'ai décidé de n'utiliser que des objets / agrégats de domaine pour maintenir la validité dans l'objet, donc uniquement lors de la mise à jour, de la création ou de la suppression. Lorsque nous recherchons des données, nous utilisons uniquement EF comme référentiel et mappons le résultat aux DTO. Cela nous permet d'optimiser les requêtes de lecture et de ne pas les adapter aux objets métier, en utilisant souvent des fonctions de base de données car elles sont rapides.

Chaque méthode de service définit son propre contrat et est donc plus facile à maintenir dans le temps. J'espère.


1
Après des années, nous sommes arrivés à la même conclusion, exactement pour les raisons que vous avez mentionnées ici.
Robert Goldwein

@RobertGoldwein C'est génial! Je me sens plus confiant dans ma décision maintenant. :-)
Niklas Wulff

@NiklasWulff: ainsi, les Dtos en question font désormais partie du contrat Application Layer, c'est-à-dire font partie du core / domain. Qu'en est-il des types de retour de l' API Web ? Exposez-vous les Dtos mentionnés dans votre réponse ou avez-vous des modèles de vue dédiés définis dans la couche API Web? Ou pour le dire différemment: mappez-vous les Dtos pour afficher les modèles?
Robotron

1
@Robotron Nous n'avons pas d'API Web, nous utilisons MVC. Donc oui, nous mappons les dto: s à différents modèles de vue. Souvent, un modèle de vue contient beaucoup d'autres éléments pour afficher la page Web, de sorte que les données du dto: s ne constituent qu'une partie du modèle de vue
Niklas Wulff

4

Jusqu'à présent, nous utilisons des modèles de domaine (principalement des entités) sur toutes les couches, et nous utilisons les DTO uniquement comme modèles de vue (dans le contrôleur, le service renvoie le (s) modèle (s) de domaine et le contrôleur crée le modèle de vue, qui est passé à la vue).

Étant donné que Domain Model fournit une terminologie ( Ubiquitous Language ) pour l'ensemble de votre application, il est préférable d'utiliser largement le Domain Model.

La seule raison d'utiliser ViewModels / DTO est une implémentation du modèle MVC dans votre application pour séparer View(tout type de couche de présentation) et Model(modèle de domaine). Dans ce cas, votre présentation et votre modèle de domaine sont faiblement couplés.

Parfois, le service doit renvoyer un objet de données qui n'a pas été défini dans le domaine, puis nous devons soit ajouter un nouvel objet au domaine qui n'est pas mappé, soit créer un objet POCO (c'est moche, car certains services renvoient des modèles de domaine, certains renvoyer effectivement les DTO).

Je suppose que vous parlez de services Application / Business / Domain Logic.

Je vous suggère de renvoyer les entités de domaine lorsque vous le pouvez. S'il est nécessaire de renvoyer des informations supplémentaires, il est acceptable de renvoyer un DTO qui contient plusieurs entités de domaine.

Parfois, les personnes qui utilisent des frameworks de troisième partie, qui génèrent des proxys sur des entités de domaine, rencontrent des difficultés pour exposer les entités de domaine à partir de leurs services, mais ce n'est qu'une mauvaise utilisation.

La question est la suivante: si nous utilisons strictement des modèles de vue, est-il acceptable de renvoyer les modèles de domaine jusqu'aux contrôleurs, ou devrions-nous toujours utiliser les DTO pour la communication avec la couche de service?

Je dirais qu'il suffit de renvoyer des entités de domaine dans 99,9% des cas.

Afin de simplifier la création de DTO et de mapper vos entités de domaine dans ces derniers, vous pouvez utiliser AutoMapper .


4

Si vous retournez une partie de votre modèle de domaine, cela devient une partie d'un contrat. Un contrat est difficile à changer, car des choses en dehors de votre contexte en dépendent. En tant que tel, vous rendriez une partie de votre modèle de domaine difficile à modifier.

Un aspect très important d'un modèle de domaine est qu'il est facile à changer. Cela nous rend flexibles aux exigences changeantes du domaine.


2

Je suggère d'analyser ces deux questions:

  1. Vos couches supérieures (c'est-à-dire afficher et visualiser les modèles / contrôleurs) consomment-elles les données d'une manière différente de ce que la couche de domaine expose? S'il y a beaucoup de cartographie en cours ou même de logique impliquée, je suggérerai de revoir votre conception: elle devrait probablement être plus proche de la façon dont les données sont réellement utilisées.

  2. Quelle est la probabilité que vous changiez profondément vos couches supérieures? (par exemple, échange d'ASP.NET pour WPF). Si cela est très différent et que votre architecture n'est pas très complexe, vous feriez peut-être mieux d'exposer autant d'entités de domaine que possible.

Je crains que ce soit un sujet assez vaste et que cela dépend vraiment de la complexité de votre système et de ses exigences.


Dans notre cas, la couche supérieure ne changera sûrement pas. Dans certains cas, le service renvoie un objet POCO assez unique (construit à partir de plusieurs domaines - par exemple, l'utilisateur et les fichiers qu'il possède), dans certains cas, un service renvoie simplement un modèle de domaine - par exemple, le résultat de "FindUserByEmail () doit renvoyer le modèle de domaine utilisateur - et voici ma préoccupation, parfois notre (nos) service (s) retourne un modèle de domaine, parfois un nouveau DTO - et je n'aime pas cette incohérence, j'ai lu autant d'articles que je pouvais et la majorité semble être d'accord que même si le modèle de domaine de mappage <-> DTO est 1: 1, le modèle de domaine ne doit pas quitter la couche de service - donc je suis déchiré.
Robert Goldwein

Dans un tel scénario et à condition que vous puissiez supporter l'effort de développement supplémentaire, j'opterais également pour le mappage afin que votre stratification soit plus cohérente.
jnovo

1

D'après mon expérience, à moins que vous n'utilisiez un modèle d'interface utilisateur OO (comme des objets nus), exposer les objets de domaine à l'interface utilisateur est une mauvaise idée. En effet, à mesure que l'application se développe, les besoins de l'interface utilisateur changent et obligent vos objets à s'adapter à ces modifications. Vous finissez par servir 2 maîtres: UI et DOMAIN, ce qui est une expérience très douloureuse. Croyez-moi, vous ne voulez pas être là. Le modèle d'interface utilisateur a pour fonction de communiquer avec l'utilisateur, le modèle DOMAIN pour contenir les règles métier et les modèles de persistance s'occupent de stocker efficacement les données. Ils répondent tous à des besoins différents de l'application. Je suis en train d'écrire un article de blog à ce sujet, je l'ajouterai quand ce sera fait.

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.