Prenons un exemple simple, concret et d’actualité…
🎄 Il était une fois… un code promo de Noël
Nous sommes début décembre.
Le sapin est en place, Mariah Carey commence à se réveiller, et le marketing débarque.
« On veut un code promo NOEL.
-50% sur tout le panier. Simple. »
Simple.
Ce mot qui, en développement, annonce rarement quelque chose de simple.
🔹 Le premier code promo (tout va bien)
On commence tranquillement.
🔹 Règle métier
-
Code promo : NOEL
-
Règle : -50% sur le total du panier
(une règle simple, tout le monde est content)
Notre petit développeur commence alors à créer son premier service PromoCodeService.
Tout fonctionne.
Le code est propre.
Il n’y a qu’une règle.
La vie est belle.
🔹 NOEL10 arrive (ça commence à sentir le sapin)
Deux jours plus tard.
« On aimerait aussi un code NOEL10 :
-10€ dès 100€ d’achat. »
Toujours simple, hein.
🔹Règle métier
-
Code promo : NOEL10
-
Règle : -10€ dès 100€ d’achat
Notre petit développeur reprend donc son service PromoCodeService.
🔹 NOEL_LIVRAISON : la livraison offerte (et là, ça commence à déraper)
Nouvelle réunion.
« On veut aussi la livraison offerte dès 50€,
sauf s’il y a un produit très lourd.
Ah, et ça s’appelle NOEL_LIVRAISON. »
🔹Règle métier
-
Code promo : NOEL_LIVRAISON
-
Règle : livraison offerte à partir de 50€ si le panier ne contient pas de produit trop lourd
Notre petit développeur ronchonne un peu… mais il reprend son service PromoCodeService.
Wahou…
Ça marche.
Mais le service devient énorme, difficile à lire et encore plus difficile à tester.
🔹NOELX2 : le coup de grâce — “un acheté, un offert”
Dernier email.
Vendredi, 17h30.
« Ah oui, dernière chose :
un produit acheté, le deuxième offert.
Code : NOELX2.
Urgent, mise en prod aujourd’hui. »
Et là… c’en est trop pour notre petit développeur.
Il se rend compte que :
-
son service est devenu monstrueux
-
les règles métier sont entremêlées
-
les tests deviennent un cauchemar
-
chaque nouveau code promo est un risque
Il se dit alors :
« Ce n’est plus possible.
Il faut que je trouve une autre solution. »
Heureusement, il existe un design pattern pour ça : le Strategy Pattern
Notre petit développeur découvre alors qu’il existe un design pattern parfaitement adapté à sa problématique :
le design pattern Stratégie.
Il commence à lire un peu de documentation et se dit :
« Tiens… mais ça pourrait être exactement ce qu’il me faut. »
Mais au fond, qu’est-ce que le Strategy Pattern ?
Pour faire simple, le design pattern Stratégie consiste à isoler chaque logique métier dans une classe dédiée.
Une stratégie = un comportement = une responsabilité claire.
Et là, notre développeur est content : il se rappelle de ses cours à la fac et réalise qu’il respecte enfin la première lettre de SOLID — le Single Responsibility Principle.
Si vous voulez une définition plus formelle (et quelques jolis schémas UML), je vous invite à consulter
la bible en la matière : Refactoring Guru.
⚠️ Attention toutefois
Il ne faut pas tomber dans la sur-architecture et l’utiliser partout.
Parfois, un simple if fait largement l’affaire… et c’est très bien comme ça.
Ok, super… mais comment on fait ça avec Symfony ?
Bonne nouvelle : le Strategy Pattern se marie très bien avec une Factory.
L’idée est simple :
-
chaque stratégie sait si elle peut gérer un code promo
-
la Factory se charge de trouver la bonne stratégie
-
le reste du code n’a plus à se poser de questions
Reprenons donc notre exemple de tout à l’heure.
Notre petit développeur revient à son problème de codes promo et décide cette fois de suivre ce design.
Une classe par logique métier
C’est parti.
Il crée une classe par type de promotion :
-
PercentagePromoCodeService (gestion de la promotion en pourcentage)
-
ValuePromoCodeService (gestion de la promotion avec une remise fixe en euros)
-
ShippingPromoCodeService (gestion de la promotion sur la livraison)
-
BuyOneGetOnePromoCodeService (gestion du coup de grâce : un acheté, un offert)
Chaque classe va implémenter la même interface, ce qui va permettre :
-
de choisir dynamiquement la bonne stratégie
-
d’appliquer la logique métier sans if ni switch
-
supports() permet de savoir si la stratégie peut gérer le code promo
-
apply() applique la logique métier associée
Exemple : PercentagePromoCodeService
Chaque classe fait une seule chose, et la fait bien.
La Factory : choisir la bonne stratégie automatiquement
Il ne reste plus qu’à créer la Factory, chargée de trouver la bonne stratégie et de l’exécuter.
Grâce à TaggedIterator, Symfony injecte automatiquement toutes les classes qui implémentent PromoCodeServiceInterface.
Pas besoin de configuration manuelle.
Pas besoin de switch.
Pas besoin de toucher à la Factory quand une nouvelle promo arrive.
Tout est prêt… et notre développeur est heureux
Toutes les classes sont en place.
Les tests sont simples, ciblés, lisibles.
Le code est clair, maintenable et surtout évolutif.
Notre petit développeur est ravi.
🔹 Nouvelle règle (encore) venant du marketing
Un mail arrive.
« Ah oui, encore une chose :
le code NOEL fonctionne trop bien,
il faudrait le restreindre aux nouveaux clients. »
🔹 Règle métier
-
Code promo : NOEL
-
Règle : -50% sur le total du panier uniquement pour les nouveaux clients
Et là… miracle.
Notre petit développeur sourit.
Il se dit :
« Parfait.
Je modifie PercentagePromoCodeService,
j’adapte le test associé,
et je ne touche à rien d’autre. »
30 minutes plus tard :
-
le code est propre
-
les tests passent
-
la mise en production se fait sans stress
Tout va bien dans le meilleur des mondes 🎄✨
Conclusion
Au départ, tout semblait simple.
Un code promo, puis deux… puis trois… et très vite, un service devenu trop gros, trop complexe et trop fragile.
Le vrai problème n’était pas Noël, ni le marketing, ni même Symfony.
C’était une accumulation de règles métier hétérogènes gérées au même endroit.
Le Strategy Pattern, combiné à une Factory, permet de répondre élégamment à ce genre de situation :
-
chaque règle métier est isolée
-
chaque promotion a sa propre responsabilité
-
le code devient lisible, testable et extensible
-
l’ajout d’une nouvelle règle n’impacte plus l’existant
Ce pattern ne rend pas le code ✨magique✨, et il ne doit pas être utilisé partout.
Mais dès que les règles métier commencent à s’accumuler, à diverger et à évoluer rapidement, il devient un allié précieux pour garder une architecture saine.
Ton futur toi (et tes collègues) te diront merci 🎄