<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: DamienGR</title>
    <description>The latest articles on DEV Community by DamienGR (@dgtech).</description>
    <link>https://dev.to/dgtech</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3649670%2F6e23073b-5bb5-4295-b39d-9cf6ecf21562.jpeg</url>
      <title>DEV Community: DamienGR</title>
      <link>https://dev.to/dgtech</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dgtech"/>
    <language>en</language>
    <item>
      <title>Drupal Service Decorators : L'art de modifier l'existant sans tout casser</title>
      <dc:creator>DamienGR</dc:creator>
      <pubDate>Fri, 19 Dec 2025 08:52:04 +0000</pubDate>
      <link>https://dev.to/dgtech/drupal-service-decorators-lart-de-modifier-lexistant-sans-tout-casser-28jp</link>
      <guid>https://dev.to/dgtech/drupal-service-decorators-lart-de-modifier-lexistant-sans-tout-casser-28jp</guid>
      <description>&lt;p&gt;On a tous connu ce moment de solitude face à une demande client un peu trop spécifique.&lt;/p&gt;

&lt;p&gt;Vous savez, ce moment où le service par défaut du cœur de Drupal fait 95% du travail, mais qu'il manque &lt;em&gt;ce&lt;/em&gt; petit détail crucial pour le projet. La tentation est grande, surtout quand on débute, de copier-coller la classe entière dans un module custom, ou pire (ne mentez pas, on a les noms), de patcher directement le fichier source en se disant "je ferai ça proprement plus tard".&lt;/p&gt;

&lt;p&gt;Soyons clairs : c'est la meilleure recette pour transformer une maintenance de routine en cauchemar lors de la prochaine mise à jour de sécurité.&lt;/p&gt;

&lt;p&gt;Heureusement, si vous cherchez à &lt;strong&gt;surcharger un service Drupal&lt;/strong&gt; proprement, l'architecture du CMS nous offre une solution élégante issue des design patterns orientés objet : le &lt;strong&gt;Drupal Service Decorator&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Au lieu de remplacer brutalement une classe ou de bidouiller des &lt;em&gt;hooks&lt;/em&gt; à n'en plus finir, le décorateur nous permet d'envelopper un service existant pour en &lt;strong&gt;modifier la logique métier&lt;/strong&gt; sans toucher à son intégrité. C’est propre, c’est pérenne, et c’est totalement intégré au conteneur de &lt;strong&gt;Drupal Dependency Injection&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Dans cet article, on va voir ensemble comment implémenter ce pattern pour altérer le comportement natif de Drupal sans jamais compromettre la stabilité de votre application. Vous allez voir, une fois qu'on a compris la mécanique du fichier &lt;code&gt;services.yml&lt;/code&gt;, c'est un outil dont on ne peut plus se passer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Partie 1 : Le concept (Promis, on fait court)
&lt;/h2&gt;

&lt;p&gt;Avant d'ouvrir votre IDE, il faut bien visualiser ce que nous allons construire. Le &lt;strong&gt;Decorator Pattern&lt;/strong&gt; n'est pas une invention spécifique à Drupal ; c'est un grand classique des &lt;strong&gt;Design Patterns&lt;/strong&gt; (merci le Gang of Four) utilisé massivement dans le développement logiciel moderne.&lt;/p&gt;

&lt;p&gt;Pour faire simple : imaginez des poupées russes.&lt;/p&gt;

&lt;p&gt;Le service original de Drupal (celui que vous voulez modifier) est la petite poupée au centre. Votre &lt;strong&gt;Service Decorator&lt;/strong&gt;, c'est la poupée plus grande qui vient englober la première.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5nn25lpfqxsfizsxk23w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5nn25lpfqxsfizsxk23w.png" alt="Schema du Service Decorator Drupal" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;De l'extérieur, pour le reste de l'application, rien ne change. Votre décorateur "ressemble" au service original car il implémente exactement la même &lt;strong&gt;Interface&lt;/strong&gt;. Mais techniquement, c'est votre classe qui intercepte les appels en premier.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pourquoi ne pas simplement faire un &lt;code&gt;extends&lt;/code&gt; ?
&lt;/h3&gt;

&lt;p&gt;C'est la question que tout développeur PHP se pose au début. &lt;em&gt;"Pourquoi s'embêter avec un décorateur alors que je pourrais juste étendre la classe originale et surcharger la méthode ?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;La réponse tient en un principe clé : &lt;strong&gt;Composition over Inheritance&lt;/strong&gt; (La composition plutôt que l'héritage).&lt;/p&gt;

&lt;p&gt;Si vous étendez directement une classe du cœur de Drupal (&lt;code&gt;extends CoreClass&lt;/code&gt;), vous créez un couplage fort. Le jour où une mise à jour mineure de Drupal modifie le constructeur de cette classe parente ou marque une méthode comme &lt;code&gt;final&lt;/code&gt;, votre site plante (WSOD).&lt;/p&gt;

&lt;p&gt;Avec un Décorateur, c'est différent :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Isolation :&lt;/strong&gt; Vous injectez le service original à l'intérieur de votre service (Composition).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Sécurité :&lt;/strong&gt; Si le code interne du service original change, votre décorateur continue souvent de fonctionner tant que l'Interface (le contrat) est respectée.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Cumulable :&lt;/strong&gt; Le plus beau ? On peut empiler plusieurs décorateurs sur un même service. Module A décore le service, puis Module B décore le résultat du Module A. C'est infiniment plus souple que l'héritage linéaire.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;En résumé, décorer un service, c'est appliquer une couche de vernis custom sur une logique existante, sans jamais rayer la peinture d'origine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Partie 2 : La mise en place technique (Le "Hard" Skill)
&lt;/h2&gt;

&lt;p&gt;La beauté du décorateur sous Drupal, c'est qu'il ne nécessite aucune librairie externe ou hack obscur. Tout se passe entre votre déclaration de service (YAML) et votre classe (PHP).&lt;/p&gt;

&lt;h3&gt;
  
  
  1. La déclaration : &lt;code&gt;services.yml&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;C'est ici que tout se joue. Pour dire à Drupal "Hé, n'utilise pas le service standard, utilise le mien à la place", nous allons utiliser la propriété magique &lt;code&gt;decorates&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Voici à quoi ressemble une déclaration typique dans votre fichier &lt;code&gt;mon_module.services.yml&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;mon_module.mon_super_decorator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Drupal\mon_module\MyServiceDecorator&lt;/span&gt;
    &lt;span class="c1"&gt;# C'est cette ligne qui fait le lien&lt;/span&gt;
    &lt;span class="na"&gt;decorates&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;system.service_original&lt;/span&gt;
    &lt;span class="c1"&gt;# La priorité définit l'ordre d'exécution si plusieurs décorateurs existent&lt;/span&gt;
    &lt;span class="na"&gt;decoration_priority&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
    &lt;span class="c1"&gt;# On masque ce service car il n'a pas vocation à être appelé directement&lt;/span&gt;
    &lt;span class="na"&gt;public&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="na"&gt;arguments&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# L'argument magique : on injecte le service qu'on est en train de remplacer !&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;@mon_module.mon_super_decorator.inner'&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;@current_user'&lt;/span&gt; &lt;span class="c1"&gt;# On peut aussi injecter d'autres services si besoin&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Les points clés pour le SEO technique (et pour que ça marche) :&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;decorates&lt;/code&gt; :&lt;/strong&gt; L'ID du service que vous voulez surcharger (ex: &lt;code&gt;entity_type.manager&lt;/code&gt; ou &lt;code&gt;logger.factory&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;.inner&lt;/code&gt; :&lt;/strong&gt; Remarquez l'argument &lt;code&gt;'@mon_module.mon_super_decorator.inner'&lt;/code&gt;. Drupal renomme automatiquement l'ancien service en lui ajoutant le suffixe &lt;code&gt;.inner&lt;/code&gt;. C'est &lt;strong&gt;crucial&lt;/strong&gt; : c'est ce qui nous permettra d'appeler la méthode originale à la fin de notre traitement.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;decoration_priority&lt;/code&gt; :&lt;/strong&gt; Plus le chiffre est élevé, plus votre décorateur sera exécuté "tôt" (c'est-à-dire qu'il sera la couche la plus externe de l'oignon).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. La Classe PHP : L'art de la délégation
&lt;/h3&gt;

&lt;p&gt;Maintenant, créons notre classe. La règle d'or ici est le &lt;strong&gt;Type Hinting&lt;/strong&gt;. Votre classe &lt;em&gt;doit&lt;/em&gt; implémenter la même Interface que le service original. Sinon, Drupal rejettera votre décorateur lors de la compilation du conteneur.&lt;/p&gt;

&lt;p&gt;Voici une structure robuste que j'utilise sur mes projets :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Drupal\mon_module&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// On importe l'interface du service original&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Drupal\Core\SomeComponent\OriginalServiceInterface&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyServiceDecorator&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;OriginalServiceInterface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="cd"&gt;/**
   * Le service original décoré (la poupée interne).
   *
   * @var \Drupal\Core\SomeComponent\OriginalServiceInterface
   */&lt;/span&gt;
  &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$innerService&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="cd"&gt;/**
   * Constructeur.
   *
   * @param \Drupal\Core\SomeComponent\OriginalServiceInterface $inner_service
   * Le service original renommé.
   */&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;OriginalServiceInterface&lt;/span&gt; &lt;span class="nv"&gt;$inner_service&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;innerService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$inner_service&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="cd"&gt;/**
   * Méthode que l'on souhaite modifier.
   */&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;laMethodeCible&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$arg1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// 1. Logique AVANT (Ex: Vérification de permission, Log)&lt;/span&gt;
    &lt;span class="c1"&gt;// ... votre code custom ...&lt;/span&gt;

    &lt;span class="c1"&gt;// 2. Appel du service original (Délégation)&lt;/span&gt;
    &lt;span class="nv"&gt;$result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;innerService&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;laMethodeCible&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$arg1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// 3. Logique APRÈS (Ex: Modification du résultat)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="cd"&gt;/**
   * L'astuce de Senior : La méthode magique __call.
   *
   * Elle permet de déléguer automatiquement toutes les autres méthodes
   * de l'interface sans avoir à les réécrire une par une.
   */&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;call_user_func_array&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;innerService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$method&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;L'astuce &lt;code&gt;__call&lt;/code&gt; :&lt;/strong&gt;&lt;br&gt;
C'est souvent ce qui différencie un code verbeux d'un code maintenable. Si l'interface du service original contient 20 méthodes et que vous ne voulez en modifier qu'une seule, utiliser &lt;code&gt;__call&lt;/code&gt; vous évite d'écrire 19 méthodes "passe-plats" inutiles.&lt;/p&gt;
&lt;h2&gt;
  
  
  Partie 3 : Cas concret – "Le Gardien des Emails"
&lt;/h2&gt;

&lt;p&gt;Passons à la pratique. Imaginons que le cahier des charges impose une restriction métier stricte : &lt;strong&gt;aucun email provenant du domaine &lt;code&gt;@spambot.com&lt;/code&gt; ne doit être considéré comme valide par Drupal.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Si vous étiez un développeur junior, vous auriez probablement cherché à utiliser un &lt;code&gt;hook_form_alter&lt;/code&gt; sur le formulaire d'inscription. Mais que se passe-t-il si l'utilisateur est créé via une API REST ? Ou via une commande Drush ? Votre hook est contourné.&lt;/p&gt;

&lt;p&gt;C'est là que le &lt;strong&gt;Service Decorator&lt;/strong&gt; brille. En surchargeant le validateur d'email au niveau le plus bas, on sécurise toutes les portes d'entrée simultanément.&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Le fichier &lt;code&gt;my_security.services.yml&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;On cible le service core &lt;code&gt;email.validator&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;my_security.email_validator_decorator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Drupal\my_security\EmailValidatorDecorator&lt;/span&gt;
    &lt;span class="c1"&gt;# On cible le service qui gère la validation des emails dans le Core&lt;/span&gt;
    &lt;span class="na"&gt;decorates&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;email.validator&lt;/span&gt;
    &lt;span class="c1"&gt;# Une priorité haute pour passer avant d'autres potentiels validateurs&lt;/span&gt;
    &lt;span class="na"&gt;decoration_priority&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
    &lt;span class="na"&gt;public&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="na"&gt;arguments&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# Injection de l'instance originale (le service natif)&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;@my_security.email_validator_decorator.inner'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. La Classe &lt;code&gt;EmailValidatorDecorator.php&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;C'est ici qu'on implémente notre logique métier. Notez l'importance de respecter l'interface &lt;code&gt;EmailValidatorInterface&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Drupal\my_security&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Drupal\Component\Utility\EmailValidatorInterface&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cd"&gt;/**
 * Décore le validateur d'email pour bloquer les domaines interdits.
 */&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EmailValidatorDecorator&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;EmailValidatorInterface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="cd"&gt;/**
   * Le service original (le coeur de Drupal).
   *
   * @var \Drupal\Component\Utility\EmailValidatorInterface
   */&lt;/span&gt;
  &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$innerService&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="cd"&gt;/**
   * Liste des domaines blacklistés (pourrait venir de la config).
   */&lt;/span&gt;
  &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$blacklistedDomains&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'spambot.com'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'evil-corp.com'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="cd"&gt;/**
   * Constructeur.
   */&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;EmailValidatorInterface&lt;/span&gt; &lt;span class="nv"&gt;$inner_service&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;innerService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$inner_service&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="cd"&gt;/**
   * {@inheritdoc}
   */&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;isValid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$checkDNS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;FALSE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// 1. Notre logique custom "AVANT"&lt;/span&gt;
    &lt;span class="c1"&gt;// On extrait le domaine de l'email&lt;/span&gt;
    &lt;span class="nv"&gt;$parts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;explode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'@'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$email&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$domain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;array_pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$parts&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;in_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$domain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;blacklistedDomains&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Si le domaine est interdit, on refuse immédiatement&lt;/span&gt;
      &lt;span class="c1"&gt;// sans même déranger le service parent.&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;FALSE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// 2. Délégation "PENDANT"&lt;/span&gt;
    &lt;span class="c1"&gt;// Si notre check passe, on laisse le service natif faire son travail&lt;/span&gt;
    &lt;span class="c1"&gt;// (vérifier la syntaxe RFC, le DNS, etc.)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;innerService&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;isValid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$checkDNS&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Pourquoi c'est élégant ?
&lt;/h3&gt;

&lt;p&gt;Regardez bien ce qui se passe dans la méthode &lt;code&gt;isValid&lt;/code&gt;.&lt;br&gt;
Si le domaine est interdit, je retourne &lt;code&gt;FALSE&lt;/code&gt; directement. Je n'appelle même pas &lt;code&gt;$this-&amp;gt;innerService-&amp;gt;isValid()&lt;/code&gt;. J'ai court-circuité la logique standard pour imposer ma règle métier, économisant au passage des ressources (pourquoi faire une vérification DNS coûteuse sur un domaine qu'on sait interdit ?).&lt;/p&gt;

&lt;p&gt;À l'inverse, si le domaine est autorisé, je rends la main au Core. Je ne réinvente pas la roue de la validation RFC des emails (ce qui serait complexe et source d'erreurs), je me contente d'ajouter ma petite couche de sécurité par-dessus.&lt;/p&gt;

&lt;p&gt;C'est ça, la puissance du décorateur : &lt;strong&gt;Intercepter, Filtrer, Déléguer.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Partie 4 : Les pièges à éviter (Parce qu'on est entre pros)
&lt;/h2&gt;

&lt;p&gt;C'est bien beau de tout décorer, mais comme tout outil puissant, il est possible de se tirer une balle dans le pied si on manque de rigueur. Voici trois points de vigilance que j'ai relevés au fil de mes projets.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. La guerre des priorités (&lt;code&gt;decoration_priority&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;Si vous utilisez plusieurs modules contribs qui décorent &lt;em&gt;tous&lt;/em&gt; le même service (par exemple &lt;code&gt;entity_type.manager&lt;/code&gt;), l'ordre d'exécution devient capital.&lt;br&gt;
Rappelez-vous de l'image de l'oignon ou des poupées russes :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Priorité haute&lt;/strong&gt; = Couche extérieure (s'exécute en premier).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Priorité basse&lt;/strong&gt; = Couche intérieure (s'exécute juste avant le service original).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Si votre décorateur doit absolument passer &lt;em&gt;avant&lt;/em&gt; un autre (pour bloquer une action par exemple), assurez-vous de définir une priorité supérieure dans votre YAML.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Le débogage peut devenir... intéressant
&lt;/h3&gt;

&lt;p&gt;Quand vous débuggez un service décoré, &lt;code&gt;get_class($service)&lt;/code&gt; ne va plus vous retourner &lt;code&gt;Drupal\Core\...\OriginalClass&lt;/code&gt;, mais &lt;code&gt;Drupal\mon_module\MonDecorateur&lt;/code&gt;.&lt;br&gt;
Si vous avez empilé 3 décorateurs, la stack trace peut devenir intimidante.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mon conseil :&lt;/strong&gt; Utilisez la commande Drush pour inspecter votre conteneur et vérifier qui décore quoi :&lt;br&gt;
&lt;code&gt;drush devel:services | grep mon_service&lt;/code&gt; (si vous avez le module Devel) ou vérifiez simplement votre compilation dans le dossier &lt;code&gt;sites/default/files/php&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Ne faites pas de la "Sur-ingénierie"
&lt;/h3&gt;

&lt;p&gt;Le décorateur est l'outil ultime quand on doit &lt;strong&gt;remplacer&lt;/strong&gt; ou &lt;strong&gt;bloquer&lt;/strong&gt; une logique.&lt;br&gt;
Cependant, si Drupal propose déjà un &lt;strong&gt;Event&lt;/strong&gt; (via &lt;code&gt;EventSubscriber&lt;/code&gt;) ou un &lt;strong&gt;Hook&lt;/strong&gt; pour faire ce que vous voulez, utilisez-les.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Besoin d'agir &lt;em&gt;après&lt;/em&gt; qu'une entité soit sauvée ? -&amp;gt; &lt;code&gt;hook_entity_insert&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Besoin de changer la façon dont l'entité est sauvée ? -&amp;gt; &lt;strong&gt;Decorateur&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Choisir le bon outil, c'est ce qui différencie le senior du bricoleur.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Le &lt;strong&gt;Drupal Service Decorator&lt;/strong&gt; est probablement l'un des patterns les plus sous-estimés par les développeurs intermédiaires. Il offre une propreté de code et une stabilité face aux mises à jour que les "hacks" à l'ancienne ne pourront jamais égaler.&lt;/p&gt;

&lt;p&gt;En maîtrisant ce concept, vous ne subissez plus l'architecture de Drupal : vous la pliez à vos besoins, proprement. C'est exactement le genre de dette technique négative (ou d'investissement technique) qui fait la différence sur la longévité d'un projet complexe.&lt;/p&gt;

&lt;p&gt;Alors la prochaine fois que vous vous apprêtez à dire à votre client "Ce n'est pas possible, c'est le fonctionnement natif de Drupal", relisez votre fichier &lt;code&gt;services.yml&lt;/code&gt;. Il y a sûrement un décorateur pour ça.&lt;/p&gt;




&lt;h3&gt;
  
  
  🚀 Besoin d'une architecture Drupal sur-mesure ?
&lt;/h3&gt;

&lt;p&gt;Vous avez un projet complexe qui nécessite de sortir des sentiers battus sans casser le Core ? Je suis développeur Drupal spécialisé dans les architectures techniques avancées et le développement de modules custom.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://dg-tech.dev/#contact" rel="noopener noreferrer"&gt;Contactez-moi pour discuter de votre projet&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Retrouvez mes autres articles sur &lt;a href="https://dg-tech.dev/blog" rel="noopener noreferrer"&gt;dg-tech.dev&lt;/a&gt;&lt;/p&gt;

</description>
      <category>french</category>
      <category>drupal</category>
      <category>designpatterns</category>
    </item>
    <item>
      <title>Au-delà du Code Coverage : Guide pratique du Mutation Testing pour des applications robustes</title>
      <dc:creator>DamienGR</dc:creator>
      <pubDate>Sun, 07 Dec 2025 09:36:38 +0000</pubDate>
      <link>https://dev.to/dgtech/au-dela-du-code-coverage-guide-pratique-du-mutation-testing-pour-des-applications-robustes-3bbo</link>
      <guid>https://dev.to/dgtech/au-dela-du-code-coverage-guide-pratique-du-mutation-testing-pour-des-applications-robustes-3bbo</guid>
      <description>&lt;p&gt;On connaît tous ce petit shot de dopamine.&lt;/p&gt;

&lt;p&gt;Vous poussez votre code, la pipeline CI/CD se lance, et quelques minutes plus tard... c'est le "Green Build". Toutes les lumières sont au vert, et votre dashboard affiche fièrement un &lt;strong&gt;Code Coverage&lt;/strong&gt; de 90% (voire 100% pour les plus zélés).&lt;/p&gt;

&lt;p&gt;Sur le papier, la &lt;strong&gt;qualité logicielle&lt;/strong&gt; semble irréprochable. Vous dormez sur vos deux oreilles.&lt;/p&gt;

&lt;p&gt;Pourtant, deux jours plus tard, un bug critique explose en production sur une fonctionnalité que vous pensiez blindée. Comment est-ce possible ? Vos &lt;strong&gt;tests automatisés&lt;/strong&gt; sont passés, non ?&lt;/p&gt;

&lt;p&gt;C’est ici qu’il faut se dire une vérité qui dérange : avoir une couverture de code élevée ne garantit absolument pas que votre application fonctionne. Cela garantit seulement que votre code a été &lt;em&gt;exécuté&lt;/em&gt;, pas qu'il a été &lt;em&gt;vérifié&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Si vous voulez vraiment dormir tranquille et assurer la &lt;strong&gt;fiabilité des tests unitaires&lt;/strong&gt;, il faut arrêter de se fier uniquement à la couverture et passer à l'étape supérieure : le &lt;strong&gt;Mutation Testing&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Dans cet article, nous allons voir pourquoi vos tests actuels vous donnent peut-être une fausse impression de sécurité, et comment l'approche "Code Coverage vs Mutation Testing" peut transformer la robustesse de vos projets web.&lt;/p&gt;

&lt;h2&gt;
  
  
  I. Le Code Coverage : Un indicateur utile, mais dangereux
&lt;/h2&gt;

&lt;p&gt;Avant de tirer à boulets rouges sur la couverture de code, soyons justes : c'est un indicateur nécessaire.&lt;/p&gt;

&lt;p&gt;Concrètement, le &lt;strong&gt;Code Coverage&lt;/strong&gt; mesure le pourcentage de lignes de votre code source qui ont été &lt;em&gt;parcourues&lt;/em&gt; lors de l'exécution de vos &lt;strong&gt;tests unitaires&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Si vous avez 10% de couverture, vous avez un problème évident : votre application est une boîte noire et chaque mise en production est un pari risqué. C’est un excellent outil pour repérer le "code mort" ou les branches logiques que vous avez totalement oublié de traiter (comme ce fameux &lt;code&gt;else&lt;/code&gt; dans votre condition qui ne se déclenche qu'une fois par an).&lt;/p&gt;

&lt;h3&gt;
  
  
  Le piège de la "Vanity Metric"
&lt;/h3&gt;

&lt;p&gt;Le problème survient quand on transforme cet indicateur en objectif absolu.&lt;/p&gt;

&lt;p&gt;En tant que développeur, je peux très facilement vous écrire une suite de tests qui affiche &lt;strong&gt;100% de coverage&lt;/strong&gt; mais qui ne teste... absolument rien.&lt;/p&gt;

&lt;p&gt;Comment ? C'est simple : il suffit d'exécuter le code sans faire d'assertions (sans vérifier le résultat).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Le Code Coverage garantit que le code a été exécuté. Il ne garantit pas qu'il a fonctionné correctement.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  L'analogie du gardien de sécurité
&lt;/h3&gt;

&lt;p&gt;Pour expliquer ça à mes clients, j'utilise souvent cette image :&lt;/p&gt;

&lt;p&gt;Imaginez que vous embauchiez un agent de sécurité pour surveiller votre maison. Sa mission est de vérifier toutes les pièces (le coverage).&lt;br&gt;
L'agent entre dans le salon, va dans la cuisine, monte dans les chambres, et ressort.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A-t-il visité 100% des pièces ? &lt;strong&gt;Oui.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;A-t-il vérifié que les fenêtres étaient fermées ? &lt;strong&gt;Non.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;A-t-il vérifié que le gaz était coupé ? &lt;strong&gt;Non.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;A-t-il vu le cambrioleur caché derrière les rideaux ? &lt;strong&gt;Non.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Il est juste "passé par là". C'est exactement ce que font beaucoup de tests automatisés : ils passent dans les fonctions pour faire monter le compteur de couverture, mais ils ne vérifient pas assez strictement les règles métier.&lt;/p&gt;

&lt;p&gt;C'est là que nous avons besoin d'un agent de sécurité plus paranoïaque. C'est là qu'intervient le &lt;strong&gt;Mutation Testing&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  II. Le Mutation Testing : Qui surveille les surveillants ?
&lt;/h2&gt;

&lt;p&gt;Si le Code Coverage vérifie si votre code est exécuté, le &lt;strong&gt;Mutation Testing&lt;/strong&gt; (ou tests de mutation) vérifie si vos tests sont &lt;strong&gt;utiles&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;La philosophie est radicalement différente. Au lieu de regarder le code, on va tester... les tests.&lt;/p&gt;

&lt;p&gt;Le principe est un peu contre-intuitif au premier abord, mais génialement efficace : pour s'assurer que vos tests sont capables de détecter des bugs, nous allons &lt;strong&gt;volontairement introduire des bugs&lt;/strong&gt; dans votre application.&lt;/p&gt;
&lt;h3&gt;
  
  
  Comment ça marche concrètement ?
&lt;/h3&gt;

&lt;p&gt;Le processus est entièrement automatisé par des &lt;strong&gt;outils de mutation testing&lt;/strong&gt; (comme Stryker, Infection ou PITest). Voici ce qui se passe dans votre pipeline :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; L'outil prend votre code source sain.&lt;/li&gt;
&lt;li&gt; Il crée une copie modifiée (un &lt;strong&gt;"Mutant"&lt;/strong&gt;) en changeant une toute petite règle logique.

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Exemple :&lt;/em&gt; Il change un &lt;code&gt;+&lt;/code&gt; en &lt;code&gt;-&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Exemple :&lt;/em&gt; Il remplace un &lt;code&gt;return true&lt;/code&gt; par &lt;code&gt;return false&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Exemple :&lt;/em&gt; Il supprime un appel de fonction.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt; Il lance votre suite de tests face à ce Mutant.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;C'est là que tout se joue.&lt;/p&gt;
&lt;h3&gt;
  
  
  "Mutant Killed" vs "Mutant Survived"
&lt;/h3&gt;

&lt;p&gt;C'est le seul moment dans votre vie de développeur où vous allez espérer que vos tests échouent.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scénario 1 : Le test passe (C'est VERT 🟢) → C'est MAUVAIS.&lt;/strong&gt;&lt;br&gt;
Le code a été saboté, mais votre test ne s'en est pas rendu compte. Il continue de dire "Tout va bien".&lt;br&gt;
Le mutant a survécu (&lt;strong&gt;Mutant Survived&lt;/strong&gt;). Cela prouve que votre test est inefficace ou incomplet sur cette partie du code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scénario 2 : Le test échoue (C'est ROUGE 🔴) → C'est BON.&lt;/strong&gt;&lt;br&gt;
Le test a détecté que le code avait changé et a levé une alerte.&lt;br&gt;
Le mutant a été tué (&lt;strong&gt;Mutant Killed&lt;/strong&gt;). Votre test est robuste : il joue bien son rôle de gardien.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Le MSI : La seule métrique de confiance
&lt;/h3&gt;

&lt;p&gt;À la fin de l'analyse, l'outil vous donne un score : le &lt;strong&gt;MSI (Mutation Score Indicator)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;C'est le pourcentage de mutants que vos tests ont réussi à tuer.&lt;br&gt;
Avoir 100% de Code Coverage avec un MSI de 50% signifie qu'une ligne de code sur deux peut être cassée sans que personne ne s'en aperçoive avant la mise en production.&lt;/p&gt;

&lt;p&gt;C'est cette métrique qui sépare les suites de tests "pour faire joli" des véritables filets de sécurité qui garantissent la &lt;strong&gt;qualité du code&lt;/strong&gt; sur le long terme.&lt;/p&gt;
&lt;h2&gt;
  
  
  III. Exemple Concret : Quand le mutant survit
&lt;/h2&gt;

&lt;p&gt;La théorie est belle, mais voyons comment cela se traduit dans votre IDE. Prenons un cas classique de logique métier : une règle d'éligibilité.&lt;/p&gt;

&lt;p&gt;Pour que tout le monde comprenne, je vais utiliser une syntaxe très simple.&lt;/p&gt;
&lt;h3&gt;
  
  
  L'erreur de frontière (Le classique)
&lt;/h3&gt;

&lt;p&gt;Imaginons une fonction simple qui détermine si un utilisateur a droit à une promotion. La règle est : &lt;em&gt;"Dépenser strictement plus de 100€"&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Le Code Source :&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isEligibleForDiscount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Vos Tests Unitaires (Coverage 100%) :&lt;/strong&gt;&lt;br&gt;
Vous écrivez deux tests logiques :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; J'envoie &lt;code&gt;50&lt;/code&gt; -&amp;gt; Je m'attends à &lt;code&gt;false&lt;/code&gt;. (OK)&lt;/li&gt;
&lt;li&gt; J'envoie &lt;code&gt;150&lt;/code&gt; -&amp;gt; Je m'attends à &lt;code&gt;true&lt;/code&gt;. (OK)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Votre suite de tests est verte. Votre coverage est à 100%. Vous êtes content.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;L'attaque du Mutant :&lt;/strong&gt;&lt;br&gt;
L'outil de mutation testing va générer un mutant en modifiant l'opérateur de comparaison. Il change &lt;code&gt;&amp;gt;&lt;/code&gt; (supérieur) par &lt;code&gt;&amp;gt;=&lt;/code&gt; (supérieur ou égal).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Code Muté par l'outil&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isEligibleForDiscount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// Le mutant est ici !&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Le Résultat :&lt;/strong&gt;&lt;br&gt;
Vos tests actuels (&lt;code&gt;50&lt;/code&gt; et &lt;code&gt;150&lt;/code&gt;) donnent exactement le même résultat avec le code original ET avec le code muté.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;50 est toujours &amp;lt; 100 (False).&lt;/li&gt;
&lt;li&gt;150 est toujours &amp;gt; 100 (True).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Verdict : Mutant Survived.&lt;/strong&gt;&lt;br&gt;
Le changement de code n'a pas été détecté. Cela signifie que si un développeur change par erreur la condition demain, ou si la règle métier change pour inclure 100€, vos tests ne vous alerteront pas. Pour tuer ce mutant, il manquait un &lt;strong&gt;cas limite&lt;/strong&gt; : un test avec la valeur &lt;code&gt;100&lt;/code&gt; exactement.&lt;/p&gt;

&lt;h3&gt;
  
  
  Les outils pour votre stack
&lt;/h3&gt;

&lt;p&gt;Peu importe votre langage de prédilection, il existe un outil mature pour implémenter cette stratégie :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;JavaScript / TypeScript :&lt;/strong&gt; &lt;strong&gt;StrykerJS&lt;/strong&gt; est la référence absolue.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PHP (Symfony/Laravel) :&lt;/strong&gt; L'excellent &lt;strong&gt;Infection PHP&lt;/strong&gt; est un &lt;em&gt;must-have&lt;/em&gt; pour les applications critiques.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Java :&lt;/strong&gt; &lt;strong&gt;PITest&lt;/strong&gt; est le standard dans le monde Enterprise.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;C# / .NET :&lt;/strong&gt; &lt;strong&gt;Stryker.NET&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  IV. Pourquoi investir là-dedans ?
&lt;/h2&gt;

&lt;p&gt;C'est souvent ici que les managers tiquent. &lt;em&gt;"Attends, tu veux lancer un outil qui va ralentir notre pipeline de déploiement pour tester des tests ?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Oui. Et voici pourquoi c'est rentable.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Réduire la dette technique (pour de vrai)
&lt;/h3&gt;

&lt;p&gt;On parle souvent de dette technique, mais rarement de comment la rembourser efficacement. Une suite de tests validée par du mutation testing est un &lt;strong&gt;filet de sécurité en béton&lt;/strong&gt;. Elle permet de refactoriser du code legacy complexe sans la peur au ventre de tout casser.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. La confiance au déploiement
&lt;/h3&gt;

&lt;p&gt;Combien coûte une heure de bug critique en production ? Combien coûte l'image de marque d'un site e-commerce qui plante pendant les soldes ?&lt;br&gt;
Le Mutation Testing demande plus de ressources CPU (c'est vrai, c'est un processus lent), mais ce coût est dérisoire comparé au coût d'un hotfix en urgence le week-end.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Astuce Pro :&lt;/strong&gt; On ne lance pas forcément le mutation testing à chaque commit. On le lance sur les Pull Requests critiques ou dans une "Nightly Build" (la nuit).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  3. Élever le niveau de l'équipe
&lt;/h3&gt;

&lt;p&gt;L'effet secondaire génial du mutation testing, c'est qu'il force les développeurs à écrire de meilleurs tests dès le départ. On arrête de tester pour le coverage, on teste pour la robustesse. C'est une montée en compétence garantie pour toute l'équipe.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion : La Qualité est un choix
&lt;/h2&gt;

&lt;p&gt;Le &lt;strong&gt;Code Coverage&lt;/strong&gt;, c'est bien. C'est le minimum syndical. Mais si votre objectif est de construire des applications web durables, maintenables et fiables, il ne suffit pas.&lt;/p&gt;

&lt;p&gt;Le &lt;strong&gt;Mutation Testing&lt;/strong&gt; est l'étape qui sépare les amateurs des professionnels soucieux de la qualité réelle. Il enlève le doute. Il remplace la confiance aveugle par la certitude mathématique.&lt;/p&gt;

&lt;p&gt;Vous préférez des lumières vertes qui vous mentent, ou des lumières rouges qui vous permettent de corriger les problèmes avant vos clients ?&lt;/p&gt;




&lt;h3&gt;
  
  
  👋 Besoin d'y voir plus clair ?
&lt;/h3&gt;

&lt;p&gt;Vous avez un doute sur la fiabilité de vos tests actuels ? Vous avez 80% de coverage mais toujours des régressions en prod ?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://dg-tech.dev/#contact" rel="noopener noreferrer"&gt;Contactez-moi pour un audit rapide&lt;/a&gt; de votre stratégie de tests.&lt;/strong&gt; Ensemble, on peut transformer votre CI/CD en véritable forteresse.&lt;/p&gt;

&lt;p&gt;Retrouvez mes autres articles sur &lt;a href="https://dg-tech.dev/blog" rel="noopener noreferrer"&gt;dg-tech.dev&lt;/a&gt;&lt;/p&gt;

</description>
      <category>french</category>
      <category>testing</category>
      <category>automation</category>
    </item>
  </channel>
</rss>
