Design Pattern : pour des règles métiers complexes et/ou changeantes
Désolé d'avance pour la longueur de ce billet ; comme ça fait longtemps que mon blog n'a pas été mis à jour, j'en profite pour faire un mini-tutoriel sur un sujet qui me tient à coeur : comment gérer les règles métier, autrement dit les Spécifications fonctionnelles, dans un projet php ?
Je pense qu'on a tous (enfin, on devrait :-) ) avoir en tête les principes SOLID. Ces principes sont étroitement liées à la notion de Complexité Cyclomatique, qui elle, est moins connue.
Derrière ce terme barbare, que vous connaissez bien si vous faites du test unitaire ou si vous utilisez des outils tels que PHPDepend, se cache en réalité quelque chose de simple : si chaque bloc conditionnel de votre projet est un noeud, la complexité cyclomatique est la somme de l'ensemble des chemins empruntable dans votre projet.
De cette manière, le code suivant :
a une complexité cyclomatique plus élevée que
Un programme maintenable est en général un programme dont la complexité cyclomatique est la plus faible possible. Et c'est justement l'enjeu de la POO de nous fournir un moyen de concevoir des applications de Complexité cyclomatique faible.
Bon, ça c'est pour comprendre le principe. Après on me dit souvent : "oui, mais moi comment je fais pour gérer mes différents cas possibles si je dois limiter mes if() ?"
Prenez cet exemple :
on a un panier de produits
on ne peut ajouter que des produits en stock
on ne peut ajouter que 20 produits maximum
la règle ci-dessus ne s'applique pas en période de fêtes
les règles ci-dessus sont susceptibles de changer souvent
Générallement on imbrique des if(), du coup on se retrouve avec un arbre applicatif assez large, c'est-à-dire de nombreux chemins possibles. A terme :
on a un risque de changement du code source très important (à chaque fois qu'on ajoute une règle métier)
on gère mal l'ajout de nouvelles règles
très vite l'algorithme devient imbuvable car trop complexe
C'est là qu'intervient la notion Specification (bon, je sais il est temps, l'intro était longue ;-) )
Ce pattern répond à : "Comment gérer mes règles métier dans mon projet". Il est généralement associé au DDD (Domain Driven Design), mais on peut l'appliquer dans n'importe quel contexte qui s'y prête.
L'idée est la suivante : chaque règle métier va être représentée par un objet (une Spécification), à qui l'on va demander si la règle est respectée :
Là où ça devient puissant, c'est qu'on va pouvoir créer des Spécifications composites pour créer des règles métiers complexes à partir d'un ensemble de règles simples :
Vous voyez les avantages : vous pouvez désormais appliquer n'importe quelle règle métier sans avoir à imbriquer plein de if() ; si vous souhaitez tester unitairement une règle, vous pouvez mocker les autres ; vos règles sont facilement évolutives...
Bon concrètement comment ça se passe ? Il faut commencer par créer notre contrat pour le fonctionnement de nos Spécifications :
Ensuite, pour permettre la création de Spécification composite il faut créer une classe abstraite générique pour nos spécifications.
Il ne nous reste plus qu'à déterminer le comportement de chacunes de nos structures de contrôle :
Pour le "et":
Pour le "ou" :
Et enfin pour le "non" :
Ca y est, on vient de se créer le minimum vital pour gérer nos règles métiers. Ca, c'est fait une bonne fois pour toute...
Maintenant dans notre projet il suffit de faire hériter nos règles de la classe Specification. Par exemple :
Et après il suffit simplement d'utiliser nos règles. Depuis PHP 5.4 on peut utiliser une interface fluide sur nos constructeurs, nous voici donc avec :
Pour synthétiser :
la Spécification permet de gérer des règles métiers
elle permet de combiner n règles métiers dynamiquement
elle facilite la gestion du changement fonctionnel
elle facile la lisibilité des règles
elle vous permet de mocker certaines parties des règles métier
ce n'est pas un remède miracle, mais elle mérite d'être plus utilisé ^^
N'hésitez pas à laisser vos retours sur ce pattern Specification, je suis curieux de savoir s'il est utilisé massivement ou non ? Ou peut-être utilisez-vous déjà un framework de gestion de règles métier, comme ceux qu'il existe dans le monde du Java ?