Introduction au Domain Driven Design

Rachida Bièche H’Midouche - 05/07/2019 à 16:44:360 commentaire

Ce post fait suite à la présentation que j'ai faite au JEDI d'Expaceo le jeudi 4 juillet dernier. Je vais reprendre les concepts généraux du Domain Driven Design qui ont été présentés lors de cette soirée. Il ne s'agit là que d'une introduction. Les références à la fin du post permettront un approfondissement des connaissances.


Introduction – Domain Driven Design


Les logiciels sont un moyen comme un autre d’arriver à une fin / d’atteindre un objectif réel. Les logiciels n’étant pas une fin en soi, ils doivent rester pratiques, utiles et ergonomiques.

Le Domain Driven Design fait référence à la conception pilotée par le métier. C’est une approche de développement de logiciels centrée sur le métier au travers de design patterns de conception (technique), des modèles conceptuels.


Eric Evans est à l’origine du concept qu’il détaille dans un livre intitulé « Domain-Driven Design, Tackling complexity in the Heart of Software », sorti en 2003. Il présente ce livre comme étant le fruit de vingt années de best practices tirées au sein de la communauté de la programmation orientée objet. 



C’est un ensemble de règles fondées sur le bon sens, d’idées, de principes et de schémas qui ambitionne le fait de mettre le métier (la compréhension des processus métier) au cœur du développement. L’idée sous-jacente est d’arriver à un langage commun compréhensible aussi bien par les experts métier que par les équipes de développement.


La conception, peut s’apparenter à des digrammes de flux de travail qui permettent d’éclater la complexité du processus métier à un niveau granulaire. En d’autres termes, il s’agit de documenter un processus métier en détail en gardant à l’esprit la notion de vulgarisation afin que n’importe qui soit capable de le comprendre. L’ensemble des parties prenantes doivent arriver à avoir une compréhension commune de la logique métier grâce au ubiquitous language notamment.


Ce ubiquitous language ou langage omniprésent sera également le langage des spécifications, des user stories, etc. Dans la mesure du possible, il faudra donc limiter le recours aux termes techniques et garder à l’esprit que le client peut accéder à mon usine logicielle, consulter mon repo, mon code source etc. s’il le souhaite et qu’il soit capable de comprendre mon code dans les grandes lignes. 


source


Ce processus d’ingestion de la modélisation métier s’appelle le Knowledge crunching. Cette activité de knowledge crunching qui est un pilier de la conception, se fait naturellement, de manière conjointe avec les développeurs et les experts métier. Il faut bien évidemment se focaliser uniquement sur les aspects utiles pour éviter de se noyer dans un flot trop important d’informations non pertinentes. Il s’agit donc de traiter une quantité importante d’information et avoir la capacité de n’en retenir que les pertinentes d’une part ; et, d’autre part, d’être capable de suffisamment la vulgariser et la simplifier afin que l’équipe entière soit en mesure de travailler à partir de ces modèles de conception. L’objectif de la modélisation est que l’équipe de développement comprenne le produit et soit en mesure de se l’approprier.




Définition Ubiquitous language


Le langage omniprésent est le point de départ du DDD. Le principe de cet ubiquitous language est que chaque classe, méthode, variable etc. doit être nommée avec le plus grand soin afin que le code raconte au travers de ses objets l’histoire du métier, que le code retranscrive au plus près les réalités métier. L'objectif du recours à un langage omniprésent est que tout le monde parle le langage métier partout même dans le code, afin de s'assurer que le code n’est pas pollué par la technique et qu'il raconte le métier.


source


Les phases de développement d’un projet avec une approche DDD 



Il existe donc une forte compatibilité avec une approche Agile du point de vue de la livraison de valeur métier de manière itérative et incrémentale.


De manière détaillée, adopter une approche DDD dans le développement de logiciels, commence par :


1.     Compréhension du métier. Le métier est donc le point d’entrée, car l’objectif de l’application est d’améliorer les processus métier.

  • Interview des spécialistes métier, échange de connaissance au travers de questions/réponses afin de mettre en évidence les concepts fondamentaux
  • Extraction de l’information essentielle auprès des spécialistes métier
  • Ebauche d’une vue d’ensemble du métier au travers d’un workflow éventuellement
  • Communication bilatérale, feedback pour affiner le croquis

 

2.     Modélisation (trait d’union des expertise métier et logicielle). Ensuite, il faut modéliser le métier en l’organisant de manière rigoureuse au travers d’un canal quelconque. C’est l’idée véhiculée qui compte et non pas le moyen retenu pour la transmettre.

La modélisation souligne la nécessité d’organiser l’information, de la systématiser (classer), de l’atomiser (ramener à un niveau granulaire), de regrouper cette granularité en modules logiques, et les traiter un à un. C’est le travail de conception qui fait partie du processus de création d’un logiciel. La modélisation nous permet de gérer la complexité. L’ensemble des processus auxquels nous pourrions penser à propos de ce métier seront donc synthétisés dans ce modèle.

 

3.     Communication. Il faut communiquer ce modèle à l’ensemble des parties prenantes (les experts métier, les développeurs, etc.) de manière précise et exhaustive sans laisser place à une quelconque ambiguïté. Ceci peut se faire de manière graphique (diagrammes, cas d’utilisation, dessins, photos, etc.) ou par écrit. Ce qui importe c’est le fait d’avoir un langage commun (ubiquitous language) intelligible par tous afin de briser d’éventuelles barrières de communication.


Architecture


source : Eric Evans


Les 4 couches conceptuelles de solution architecturale pour des conceptions pilotées par le métier selon Eric Evans sont


1- Interface

  • Présentation des informations aux utilisateurs
  • Interprétation des actions utilisateurs


2- Application

  • Coordination des activités de l’application
  • Ne contient aucune logique métier
  • Ne conserve pas l’état d’un objet métier mais peut conserver l’état de la progression d’une tâche applicative


3- Métier / Domaine

  • Contient l’ensemble des informations relatives au métier
  • Cœur du logiciel métier
  • Conserve l’état des objets métier


4- Infrastructure

  • Se comporte comme une bibliothèque de support à l’ensemble des autres couches
  • Fournit des outils de communication entre les couches
  • Se charge de la persistance des objets métier
  • Gère les accès à la base de données


Model-driven design - DDD Tactical patterns


Voici le schéma des patterns tactiques d'Eric Evans qui présente les éléments clefs de la modélisation objet et de la conception de logiciels du point de vue domain-driven design. L'objectif de la modélisation est que notre code parle la langue du métier, de retrouver le langage métier dans le code avec la bonne signification. L'output de ce processus de modélisation doit retranscrire :

  • Le modèle ou un sous-ensemble du modèle
  • Les objets du modèle et les relations entre eux
  • Les comportements des objets
  • Eventuellement les contraintes


source


De manière simpliste, à partir des spécifications métier, les noms sont convertis en classes et les verbes en méthodes. Au niveau structure du code, le nom des variables doit raconter une histoire, celui d’une méthode exprimer un comportement. Je dois retrouver dans ma modélisation, le vocabulaire de mon ubiquitous language. Je découvre comment ces objets s’accordent entre eux pour faire des actions. J’apprends le métier en lisant le code… Les tactical patterns du DDD m'aiguillent sur la manière de faire cela concrétement.


Cartographie des modèles et de leurs relations


Les Entités

Les entités sont des catégories d’objet qui ont une identité qui au-delà des attributs qu’ils possèdent conservent une certaine continuité et une identité unique (i.e. une personne, un compte bancaire) pendant leur cycle de vie. Ceci peut se matérialiser au travers d’un identifiant unique, d’une clef primaire unique, etc.

Ces objets sont des objets fondamentaux du modèle et doivent être identifiés dès le début du processus de modélisation.


Value objects (objets-valeurs)

Un objet valeur, est une classe utilisée pour décrire certains aspects d’un domaine (métier), et qui ne possède pas une identité. Ici nous sommes intéressés par les attributs que possèdent l’objet et non pas son unicité. Ces objets-valeurs peuvent être créés et détruits lorsqu’ils ne sont plus référencés par un objet. Ces objets-valeurs doivent être immuables pendant leur durée de vie. Si l’on souhaite qu’ils aient une valeur différente, vaut mieux en créer un autre.

Etant donné que ce sont des objets sans identité et immuables, les objets-valeurs peuvent donc être partagés. Ceci permet de garantir l’intégrité de la donnée.

Les objets-valeurs sont utilisés pour contenir des attributs d’un objet métier.


Services

Lorsque nous définissons le ubiquitous language, les concepts clefs du métier sont introduits dans le langage. Les noms du langage sont reproduits en objets, en classes. Les verbes du langage associés aux noms correspondants deviennent une partie du comportement de ces objets, des méthodes.

En revanche, il arrive parfois qu’il y ait des comportements actions, verbes du domaine métier qui ne peuvent être associés à un objet en particulier. Il peut s’agir d’un comportement partagé entre diverses classes mais qui ne peut être lié à aucune directement pour autant.

On peut déclarer un tel comportement comme un Service dont le seul rôle est de fournir une fonctionnalité au métier au service des entités et des objets-valeurs. Le Service encapsule un concept. Les Services agissent comme les Interfaces qui fournissent des opérations, on peut les utiliser dans la couche métier. Le Service est un point de connexion entre plusieurs objets.


Modules

Les Modules sont une méthode qui permet d’organiser des concepts et des tâches qui ont un lien les uns avec les autres de manière à réduire la complexité. Ceci est notamment important pour les applications larges et complexes, pour lesquels le modèle à tendance à grossir à un point où il devient difficile de l’appréhender comme un tout et de comprendre les relations et les interactions entre ses différents composants.

Cette gestion de la complexité consiste à définir plusieurs modules à un projet, les relations entre les modules, comprendre les interactions entre eux et ensuite seulement regarder les détails à l’intérieur d’un module.

Recourir aux modules permet de garantir aussi la qualité du code. Le code doit avoir un niveau élevé de cohésion et un faible niveau de couplage.


Agrégats / Factories / Repositories

Les objets du domaine traversent un certain nombre d’états pendant leur durée de vie. Ces objets sont créés, placés en mémoire, utilisés pendant les traitements, sauvegardés dans des endroits permanents et ensuite détruits.

Il existe trois patterns qui peuvent gérer cela. Les agrégats permettent de définir la propriété et les frontières des objets. Ils peuvent être composés d’une entité + value object. Les factories et repositories permettent de gérer la création et le stockage des objets. La Factory crée des objets tandis que le Repository reconstruit des objets existants.


Model-driven design - DDD Strategic design patterns


Préserver l’intégrité du modèle

La consistance interne du modèle est appelée l’unification. Plutôt que d’essayer de maintenir un gros modèle qui ne va pas tenir sur le long terme, il est préférable de procéder à un découpage entre plusieurs modèles (bounded context by domain). Plusieurs projets bien intégrés peuvent évoluer indépendamment tant qu’ils respectent le contrat qui les lie. Chaque modèle doit avoir une frontière parfaitement délimitée, et les relations entre les modèles doivent être définies avec précision. C’est dans ce contexte qu’interviennent les Strategic design patterns du DDD.


DDD Strategic design patterns


Un bounded context n’est pas un module. Un contexte délimité fournit le cadre logique au sein duquel le module évolue. Les modules sont utilisés pour organiser les éléments d’un modèle, donc le contexte délimité inclue / englobe le module.

L’aspect négatif découle du fait qu’avoir plusieurs modèles implique que les frontières doivent être définies ainsi que les relations entre les modèles.



Continuous integration / Intégration continue

L’intégration continue est un process nécessaire dans le cadre d’un contexte délimité. Ce process d’intégration permet de s’assurer que l’ensemble des nouveaux éléments qui sont ajoutés correspondent de manière harmonieuse au reste du modèle, et sont correctement implémentés dans le code.


Context map / Carte de contexte

Il est conseillé d’utiliser le contexte sur la base de l’organisation de l’équipe. Les individus appartenant à la même équipe peuvent communiquer plus facilement, et peuvent faire un meilleur travail d’intégration et d’implémentation du modèle. Si chaque équipe travaille sur son propre modèle, il est préférable que tout le monde ait une idée de la vue d’ensemble / vision globale.

Un contexte map est un document qui esquisse les différents Bounded Context ainsi que les relations entre eux. Un Context map peut être un diagramme ou un document écrit. Le niveau de détail peut varier.


Il n’est pas suffisant d’avoir des modèles unifiés séparés. Ils doivent être intégrés, car la fonctionnalité de chaque modèle fait partie du système entier / dans son ensemble. A la fin, les bouts doivent être assemblés, et le système dans son ensemble doit fonctionner correctement.


Interactions entre les différents contextes


Il existe un certain nombre de patterns qui peuvent être utilisés pour définir les relations entre les contextes.

Le Shared Kernel (Noyau Partagé) et le Customer Supplier (Client fournisseur) sont des patterns qui présentent un fort niveau d’interaction voir de dépendance entre les contextes. Le pattern Conformist implique que l’équipe client adhère au modèle de l’équipe fournisseur, en s’y conformant entièrement. Separate Ways (Chemin Séparés) est un pattern utilisé lorsque l’on veut que les contextes soient très indépendants les uns vis-à-vis des autres (y compris d’un point de vue technologique) et qu’ils évoluent séparément. Les Open Host Services (Services Hôtes) consistent à définir un protocole qui donne l’accès à notre sous-système comme un ensemble de Services.

La couche Anticorruption agit comme traducteur entre deux modèles tout en les isolant l’un de l’autre.


Conclusion


Le Domain-Driven Design c’est avoir un modèle d’application qui dénote une compréhension poussée du métier. DDD c’est un système de techniques de modélisation et de conception qui peuvent être utilisées pour mettre en accord des systèmes logiciels complexes avec des besoins métier tout en maintenant les projets agiles.

Le DDD n'est pas pertinents pour tous les projets et contextes. Il faut que la complexité, la valeur, et le risque soient dans le métier, dans le core domain ; et, que cela nécessite que l'on s'imprègne du domaine.


source


Références


https://medium.com/the-coding-matrix/ddd-101-the-5-minute-tour-7a3037cf53b8

A Summary of Eric Evans’ Domain-Driven Design (Tackling complexity in the heart of software) http://www.lulu.com/shop/floyd-marinescu-and-abel-avram/domain-driven-design-quickly/paperback/product-2117794.html

https://www.briisk.co/blog/event-driven-architecture-and-ddd/

https://blog.scottlogic.com/2018/03/28/domain-driven-design.html 

https://www.infoq.com/articles/ddd-in-practice/

https://dotnettutorials.net/lesson/dependency-injection-design-pattern-csharp/

http://dddcommunity.org/#DDD

https://www.canal-u.tv/video/centre_d_enseignement_multimedia_universitaire_c_e_m_u/06_atelier_2_domain_driven_design_pour_de_vrai_pa2017.36403

Commentaires :

Aucun commentaires pour le moment


Laissez un commentaire :

Réalisé par
Expaceo