Définition des odeurs de code

Publié le 13 juillet 2026
Gros plan sur le visage d’un homme en colère
By Dave Bergmann

Le « Code smell » (ou odeur de code) est un terme informel utilisé par les programmeurs pour décrire les schémas de conception logicielle communs aux mauvais codes. Il convient d’appréhender les odeurs de code non pas comme des bugs ou des défauts en eux-mêmes, mais comme des signes avant-coureurs d’une mauvaise qualité du code.

Le terme « code smell » a été inventé par Kent Beck et popularisé dans l’ouvrage fondateur de 1999 qu’il a co-écrit avec Martin Fowler, Refactoring : Improving the Design of Existing Code— plus précisément, dans le chapitre intitulé « Bad Smells in Code ». Martin Fowler lui-même définit succinctement une odeur de code comme « une indication superficielle qui correspond généralement à un problème plus profond du système ».1  

Contrairement à un véritable bug logiciel, une odeur de code n’empêche pas le code source de compiler, exécuter et accomplir sa fonction souhaitée, et sa présence n’indique pas toujours un problème réel. Imaginez que vous entriez dans une maison et que vous sentiez une odeur bizarre ou de moisi. Cette odeur pourrait provenir d’aliments périmés dans votre réfrigérateur ou de déchets qu’il faudrait sortir ; plus grave encore, cela pourrait être du à de la moisissure ou à quelque chose qui pourrit dans vos murs, mais elle pourrait aussi simplement provenir d’un fromage à l’odeur très forte, tout à fait propre à la consommation. Quoi qu’il en soit, l’odeur concernée nécessite votre attention.

Pour un ingénieur logiciel expérimenté, certains modèles de code ne « sentent » tout simplement pas bon. Au fil du temps, on peut associer instinctivement leur présence à certaines complications, inefficacités ou problèmes futurs. Le fait de nommer et de vulgariser des odeurs de code spécifiques permet de se familiariser avec ces modèles contreproductifs (ou « anti-modèles ») et les principes de conception qu’ils enfreignent. Cette familiarité, à son tour, augmente la probabilité que ces anti-modèles soient repérés et corrigés lors de l’analyse du code. Comme le dit M. Fowler, « une odeur est par définition quelque chose qu’il est facile de détecter ou de sentir ».

Les odeurs de code, si elles ne sont pas traitées, contribuent largement à la dette technique. Comme l’affirme une étude, 75 % des défauts d’analyse n’affectent pas l’exécution du programme mais ont « un impact sur l’évolutivité du logiciel ».2 Même si un certain anti-modèle ou une mauvaise habitude ne provoque pas de bug aujourd’hui, cela augmente considérablement le risque de bugs, de plantages ou de vulnérabilités de sécurité dans votre base de code par la suite. La présence d’odeurs de code connues réduit au minimum la lisibilité et la maintenabilité de votre code, ce qui le rend plus difficile à comprendre, à mettre à jour et à améliorer.

Les types d’odeurs de code

Bien que de nombreuses odeurs de code courantes continuent d’être connues sous les noms inventés par Beck et Fowler dans Refactoring, il n’existe pas de liste canonique et universellement acceptée d’odeurs de code. Cependant, qu’une odeur de code donnée doive être désignée par un nom ou un autre, ou être classée comme étant son propre anti-modèle plutôt que comme un sous-type d’un autre, n’a aucune importance. Ce qui importe, c’est que le nom et la description d’une odeur de code soient suffisamment clairs et intuitifs pour aider les équipes de développement logiciel à partager et à mettre en œuvre des principes de conception productive.

De même, il n’existe pas de taxonomie universellement acceptée pour les différentes catégories d’odeurs de code. Cet article s’appuie principalement sur la taxonomie proposée par Jerzyk et Madeyski en 2023.3 Leurs résultats ont été publiés dans le catalogue utile tenu à codesmells.org, qui fournit un contexte supplémentaire, des exemples de code et des techniques de refactoring appropriées pour chacun.

Jerzyk et Madeyski soulignent que la taxonomie des défauts de code la plus souvent citée suit les cinq groupes proposés par Mäntylä et Lassenius en 2006, qui ont catégorisé les 22 défauts de code introduits par Fowler et Beck (et un autre de leur propre invention) en cinq groupes distincts : Bloaters, Abuseurs orientés objet, Bloqueurs de changement, Éléments superflus and Coupleurs.4 Après leur propre tentative d’avis exhaustif à la fois de la littérature officiellement publiée et du « contenu gris » (comme des blogs, forums et wikis), Jerzyk et Madeyski ont catalogué 56 odeurs de code différentes en 9 groupes (dont les 5 mentionnés plus tôt dans ce paragraphe).

Bien que cette section suive principalement la structure des 9 catégories qu’ils ont proposée, il est important de noter que ces regroupements sont informels et subjectifs : la taxonomie la plus utile est celle qui vous semble la plus intuitive. Comprendre les différents types de complications ou d’inefficacités que les odeurs de code peuvent entraîner permet d’acquérir une vision plus pertinente de ces derniers que la simple mémorisation mécanique de chaque cas particulier. Comme le souligne M. Mäntylä, « face à une longue liste de défauts de conception du code, il est facile de perdre de vue l’ensemble ». 5 

Bloaters

Les bloaters sont des odeurs de code qui font souvent grossir les méthodes, les classes ou les blocs de code au point de les rendre difficiles à manier. Cela diminue la lisibilité et rend le code plus difficile à maintenir ou à modifier.

Voici quelques exemples de blocages :

  • Groupes de données : groupes de variables qui apparaissent fréquemment ensemble partout.

  • Classe volumineuse : une classe qui tente d’en faire trop et qui contient trop de variables, manquant de cohésion.

  • Fonction longue (méthode longue) : une méthode contenant trop de lignes de code.

  • Longue liste de paramètres : Fonctions nécessitant trop d'arguments pour fonctionner correctement.

  • Obsession primitive : utiliser des types de données primitifs au lieu de petits objets spécialisés.

Bloqueurs de changement

Les bloqueurs de changement, comme leur nom l’indique, sont des odeurs de code qui empêchent de modifier, d’ajouter ou de développer des logiciels. Le cas typique d’un obstacle au changement est une structure de code qui vous oblige à effectuer une série de modifications à plusieurs endroits afin d’implémenter une seule modification simple.

Ce type d’odeur de code enfreint le principe de responsabilité unique (SRP) de Robert C. Martin, selon lequel les modifications apportées à un module de code ne doivent provenir que d’un seul endroit. Comme le suggère M. Martin dans un article de blog sur la SRP : « Rassemblez les éléments qui changent pour les mêmes raisons. » Séparez les choses qui changent pour différentes raisons. » 6

Voici des exemples d’obstacles au changement :

  • Shotgun surgery : la mise en œuvre d’un seul changement nécessite d’apporter simultanément des modifications à de nombreux modules dispersés (ce qui est en quelque sorte le contraire d’une classe de grande taille).

  • Changement divergent : à l’inverse du shotgun surgery, la mise en œuvre d’un seul changement nécessite de nombreuses modifications au sein d’une même classe.

  • Callback hell : structure de code dans laquelle de nombreuses méthodes sont imbriquées les unes dans les autres à plusieurs niveaux, avec de nombreux retours à la ligne et accolades, ce qui masque les relations de cause à effet et rend le code difficile à lire et à maintenir.

Coupleurs

Les coupleurs sont des odeurs de code qui violent le principe fondamental de conception de faible couplage en créant des dépendances excessives entre différentes classes. Cela réduit la réutilisation du code et complique (voire empêche) les tests unitaires indépendants.

Voici des exemples de coupleurs :

  • Feature envy : une méthode accède excessivement aux données d’un autre objet.

  • Délit d’initié (ou relation inappropriée) : une classe utilise les champs ou méthodes internes d’une autre classe.

  • Chaînes de messages : longue séquence d’appels de méthode enchaînés entre des objets.

Distributeurs de données

Les distributeurs de données transmettent des données vers bien plus de classes ou de fonctions que nécessaire. Cela crée des dépendances et une complexité inutiles, aboutissant souvent à des éléments de code qui se contentent de stocker ou de distribuer des données sans fournir de comportement significatif.

Voici quelques exemples de distributeurs de données :

  • Intermédiaire : classe dont le seul rôle est de déléguer aux autres.

  • Tramp data : lorsque les données « font de l’auto-stop » selon une chaîne de méthodes qui ne les utilisent pas.

  • Données globales : structure dans laquelle les variables peuvent être modifiées depuis n’importe quel endroit du code source, ce qui rend chaque fonction du code source potentiellement suspecte en cas de problème.

Éléments superflus

Les éléments superflus sont, intuitivement, des éléments de code inutiles : leur suppression rendrait le code source plus propre et plus facile à lire sans impact significatif sur la fonctionnalité globale.

Voici quelques exemples d’éléments superflus :

  • Commentaires : bien que les commentaires soient généralement une bonne chose, ils sont parfois utilisés comme un « désodorisant » pour masquer les problèmes de code, expliquant plutôt qu’améliorant. Par exemple, si un commentaire décrit ce qui se passe dans une section particulière du code, il sert à masquer un code qui n’est pas suffisamment intuitif ou lisible en soi. Les commentaires individuels peuvent également devenir redondants ou obsolètes au fil du temps. Des comportements de commentaires plus spécifiques apparaissent dans d’autres odeurs de code.

  • Classe de données : classes contenant uniquement des champs et des accesseurs, sans comportement significatif.

  • Code mort : des éléments de code qui ne sont plus exécutés car, avec le temps, le refactoring et d’autres modifications les ont rendus obsolètes.

  • Code en double : des structures de code identiques ou très similaires à plusieurs endroits.

  • Classe paresseuse (alias éléments paresseux) : classes ou fonctions qui font trop peu pour exister.

  • Généralité spéculative : ajout de code inutile pour prendre en charge de futures fonctionnalités hypothétiques.

Abuseurs fonctionnels

Les abuseurs fonctionnels sont des odeurs de code qui vont à l’encontre des principes de programmation orientée objet en introduisant des modèles fonctionnels dans une base de code orientée objet.

Voici des exemples d’abuseurs fonctionnels :

  • Boucles : utilisation des boucles traditionnelles au lieu des opérations modernes. Bien que M. Fowler considérait presque toutes les boucles comme dépassées, M. Jerzyk a avancé que les boucles impératives, en particulier, sont le principal problème.

  • Données mutables : variables dont l’état change de façon inattendue, provoquant des effets secondaires imprévisibles.

  • Effets secondaires (ou fonctions impures) : méthodes qui font plus que ce que leur nom et leur objectif principal n’indiquent.

Abuseurs lexicaux

Les abus lexicaux sont des défauts de codage dus à de mauvaises conventions de nommage, à une mise en forme incohérente ou à une syntaxe cryptique. En d’autres termes, il s’agit de cas où la formulation du code ne correspond pas intuitivement au comportement correspondant, ce qui nuit à la lisibilité.

 Voici quelques exemples d’abus lexicaux :

  • Nombre magique : nombres anonymes insérés dans le code sans explication ni contexte adéquats.

  • Commentaire fallacieux : commentaires qui ne sont plus exacts car le code qui les entoure a changé. Comme les commentaires ne sont pas réellement exécutés, ils échappent souvent aux linters et autres vérifications automatiques.

  • Nom mystérieux : fonctions ou variables mal nommées, cachant leur véritable intention. 

  • Nom de méthode fallacieux : fonctions dont le nom est activement trompeur, compte tenu des conventions et attentes courantes. Par exemple, une fonction appelée getSomething qui en réalité ne renvoie rien.

Obfuscateurs

Les obfuscateurs sont des éléments de code écrits d’une manière inutilement alambiquée, complexe ou « intelligente » qui dissimulent l’intention sous-jacente du code derrière des abstractions inutiles. Ces odeurs de code rendent le code source difficile à lire et il sera donc difficile pour les programmeurs à l’avenir de le comprendre et de le modifier selon les besoins.

Exemples d’obfuscateurs :

  • Séparation verticale : des distances inutilement grandes entre des éléments de code liés et pertinents, comme une variable déclarée en haut d’une méthode qui n’est utilisée que 50 lignes plus tard.

  • Intention masquée : catégorie plus large de fonctions, de variables, de noms et de chiffres dont l’objectif n’est ni intuitif ni clairement défini dans son contexte.

  • Expression booléenne compliquée : flux logiques alambiqués, tels que ceux contenant des doubles négatifs ou des chaînes complexes de IF et IF NOT et AND et AND NOT .

  • Code astucieux : code fonctionnel qui utilise un langage spécifique difficile à suivre dans des situations où il existe déjà des fonctions intégrées largement comprises et d’autres solutions conventionnelles.

Abuseurs orientés objet

Les abuseurs orientés objet (ou agresseurs orientés objet) sont des odeurs de code qui n’appliquent pas complètement ou correctement les principes de la conception orientée objet. Par exemple, les instructions switch sont utiles en programmation procédurale, mais il faut les éviter en programmation orientée objet.

Voici quelques exemples d’agresseurs orientés objet :

  • Classe alternative avec différentes interfaces : classes exécutant des fonctions similaires en utilisant des noms de méthodes complètement différents.

  • Héritage refusé : sous-classes qui n’ont pas besoin ou n’utilisent pas de méthodes héritées.

  • Instructions switch (également appelées complexité conditionnelle ou instructions switch répétées) : la même instruction switch dupliquée dans tout le code source.

  • Champ temporaire : variable créée là où elle n’est souvent pas nécessaire, généralement utilisée uniquement dans certaines circonstances.

Restructuration des odeurs de code

Le principal avantage de comprendre les odeurs de code réside dans le fait que leur identification permet une refactoring plus efficace : pratique consistant à mettre à jour le code source sans en modifier le comportement externe ni les fonctionnalités. Un refactoring est essentiel pour réduire la dette technique et permettre des améliorations rapides et efficaces, ainsi que l’ajout à votre base de code au fil du temps.

Le refactoring peut être compris dans une large mesure comme le processus d’identification et d’adresse des odeurs de code. Son objectif est de résoudre les problèmes avant qu’ils n’affectent les fonctionnalités ; le processus s’apparente davantage à un débogage qu’à un refactoring.

Les plateformes d’ingénierie agentique modernes, telles qu’IBM Bob, proposent souvent des suggestions de refactoring automatisées en temps réel. Grâce à une formation approfondie sur les odeurs de code courants dans le contexte de bases de code réelles, en lieu et place d’une mémorisation par cœur des définitions de ces odeurs de code, les capacités de refactoring de code par IA de ces plateformes permettent aux développeurs d’augmenter leur productivité sans pour autant voir alourdir le code généré par l’IA, qui serait alors difficile à comprendre et à modifier par la suite.

Auteur

Dave Bergmann

Senior Staff Writer, AI Models

IBM Think

Solutions connexes
IBM Bob

Accélérez la livraison de logiciels grâce à IBM Bob, votre partenaire d’IA pour un développement sécurisé et sensible aux intentions.

Découvrir IBM Bob
Solutions d’IA destinées aux développeurs

Développez, déployez et gérez plus rapidement des applications d’IA grâce à des outils adaptés aux entreprises.

Découvrir l’IA pour les développeurs
Services de modernisation des applications

Repensez vos systèmes hérités grâce à une modernisation intelligente basée sur l’IA.

Découvrir nos services de modernisation des applications
Passer à l’étape suivante

Exploitez l’IA générative et l’automatisation avancée pour produire du code prêt à l’emploi avec davantage de rapidité et de cohérence. Les modèles Bob renforcent les compétences de vos développeurs, rationalisent vos workflows de modernisation et simplifient vos tâches de développement complexes.

  1. Découvrir notre agent de codage basé sur l’IA
  2. Découvrir nos solutions d’IA destinées aux développeurs