Glsr, le DDD et les tests

Posté le vendredi 10 novembre 2023
Glsr, le DDD et les tests

J'ai fait mes premiers tests avec Symfony et l'architecture hexagonale avec les formations proposées par T. Boileau (@toham) sur Twitch et YouTube. Préparez-vous une bonne plage de temps, les vidéos durent 3 à 4h chacune. 😋

Il y a trois ans, j'avais repris le dev en autodidacte, et avais été approché pour intégrer une équipe de dev, en bénévole. Mon contact connaissait bien PHP et symfony, mais n'avait jamais utilisé les tests 😒.

Pas de soucis, j'avais été initié à cette pratique quelques semaines auparavant, après avoir visionné et lu un grand nombre de vidéos et articles sur le sujet sans résultat probant. 

Mon projet, qui était à l'abandon depuis plusieurs mois, ne demandait qu'à repartir de zéro. Encore une fois 😋

Nouveau repo GitHub et me voilà parti à réécrire mes entités, à commencer par des tests d'instanciation (il faut bien se faire la main 😇). Ce que j'ai ajouté de nouveau, c'était une vision différente de l'entité. Mon initiateur aux tests, @senzowayne, m'avait aussi fait une approche des prémices du DDD et de la clean architecture. Je ne parlais plus d'entités ORM (en relation avec une base de données), mais d'agrégats, de composants et d'objets de valeurs. 

Pour ce faire, il ne faut plus penser en fonction de la base de données, mais en fonction du métier pour lequel on développe.  C'est ce que l'on appel de développement dirigé par le domaine (Domain Driven Development). Rien de plus simple pour moi en tant qu'ancien responsable de restaurant reconverti, le sujet est la gestion des stocks pour métier de bouche.

Donc, je commence à réfléchir au découpage des différents domaines sur lesquels je vais baser mon application. Je parle de cette approche dans mon article sur le Behavior Driven Development. Je remarque rapidement que chaque cas d'utilisation (use case) principal fait émerger plusieurs schémas d'objets. Si l'on commence avec les inventaires, par exemple, l'élément central est l'"Article", un aggrégat. Ce qui s'y rattache n'est que valeur ou composant. La différence entre les deux est l'identité

Oui, un article a une identité propre, et deux articles n'auront pas la même selon le fournisseur, la date d’achat ou le prix. Le "Fournisseur" quant à lui, a aussi une identité, et donc ne sera pas considéré comme une valeur (‘value object’, dans le jargon technique 😉) mais comme un composant de l'article. Il sera lui-même un agrégat avec les propriétés nécessaires pour l'inventaire. Seule une référence de celui-ci sera passée dans l'agrégat Article.

Test Value ObjectUn Value Object (VO) n'a pas d'identité : une catégorie, une taxe, une quantité, ne sont que des éléments qui permettent de préciser l'identité de l'agrégat et de son noyau principal ('aggregate root'), l'Article. Le gros avantage, c'est qu'ils peuvent servir à valider l'agrégat ; ce qui permet de retirer toute la "magie" que peuvent apporter des librairies comme Doctrine ou le composant "Validator" de Symfony. Par exemple, le libellé de l'article n'est plus une simple chaîne de caractères (string), mais un VO ArticleLabel, qui recevra une string, et pourra être vérifié et/ou transformé (longueur de texte, capitaliser, ajout de préfixe…). Sa valeur sera disponible à travers un accesseur (appelé aussi getter). Dans le même esprit, le prix de l'article sera un ArticleAmount, pouvant être initié avec le prix unitaire. Pour une bonne pratique, ces montants seront en nombre entier, pas en décimal (10,00€ => 1000 cts), et leurs getter pourront renvoyer un entier, ou sont homologue décimal suivant le besoin (besoin métier pour des calculs, ou pour l'affichage monétaire).

Pour en revenir aux tests, l'avantage de cette approche permet de tester unitairement chaque VO, pour tous les cas possibles. Par exemple, la quantité d'un article, comme son prix unitaire, ne pourra jamais être négative. Cette règle d'acceptance est vérifiée par le VO.

 

 

 

 

 

 

Ainsi, notre entité aura toujours des attributs au bon format/type, et cette façon de faire évite toute dépendance à quelque framework que ce soit. Bien sûr, des librairies telles que beberlei/Assert, ou des fonctions natives de PHP peuvent être utilisées pour valider vos VO.

Cette bonne pratique permet dans le cas de changement d'implémentation future de pouvoir récupérer le Domain dans son intégralité, et de le consommer avec un autre framework, de le brancher sur un autre type de base de données (MySql, PostgreSql, Sqlite… ). C'est le gros avantage de l'architecture hexagonale

C'est notamment ce qui va me servir pour reprendre mon projet sous une nouvelle approche. Mais ce sera l'objet d'un autre article. 😉

Bon code 

Image par Foundry Co de Pixabay