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.
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.
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.
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.
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.
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.
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
2- Application
3- Métier / Domaine
4- Infrastructure
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 :
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.
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.
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.
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.
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/
Commentaires :
Aucun commentaires pour le moment
Laissez un commentaire :