Supprimer du code mort : le refactoring le plus rentable
J'ai supprimé 40% du code d'une application. Elle est devenue 3x plus rapide.
Pas de nouvelle architecture. Pas de migration vers un framework dernier cri. Pas de réécriture complète.
Juste du code supprimé.
C'est le refacto dont personne ne parle, parce qu'il n'est pas sexy. On ne met pas "migration microservices" sur son CV en supprimant des fichiers. Pourtant, sur cette base de code, c'est la seule intervention qui a eu un impact mesurable sur la performance.
Pourquoi le code mort est plus dangereux que le mauvais code
Un mauvais code, on le voit. Il ralentit une PR, il fait échouer une review, un dev finit par s'énerver dessus et le corrige. Le code mort, lui, ne fait de bruit nulle part. Il compile, il passe les tests, personne ne le lit plus. Il grossit le bundle, complique la navigation dans le repo, et personne ne sait s'il est encore utile - donc personne n'y touche.
C'est exactement ce que j'ai trouvé en auditant cette base de code.
1. Des features mortes que personne n'avait osé toucher
Du code fonctionnel, testé, documenté. Pour des fonctionnalités que plus personne n'utilisait depuis 18 mois. Personne ne l'avait supprimé, parce que personne ne savait si un client, quelque part, en avait encore besoin.
Le doute conserve plus de code mort que n'importe quelle mauvaise pratique. Une feature non utilisée, avec une équipe qui doute, reste en prod indéfiniment - alors qu'elle continue de charger, de s'exécuter, et de peser sur chaque build.
2. Des abstractions construites pour des problèmes qui n'ont jamais existé
Des couches d'architecture élégantes, prévues pour "quand on va scaler". La startup n'avait pas scalé. Les abstractions étaient toujours là.
Elles ralentissaient l'exécution - des indirections inutiles, des factories pour un seul cas d'usage, des interfaces pour une implémentation unique - et compliquaient la lecture du code pour chaque nouveau dev qui arrivait. Ce genre d'abstraction, c'est du premature optimization version architecture : on paie le coût de la flexibilité avant d'avoir le problème qu'elle résout.
3. Des dépendances installées "au cas où"
Des librairies importées pour une feature abandonnée, des utilitaires jamais appelés, des packages maintenus pour rien. Chaque dépendance inutile, c'est un vecteur de vulnérabilité potentiel, du poids en plus dans le bundle final, et un npm install qui dure 30 secondes de trop à chaque déploiement.
Multiplié par le nombre de développeurs, de CI runs et de déploiements sur la durée de vie d'un projet, ces 30 secondes représentent des heures perdues pour rien.
Le meilleur code est celui qui n'existe pas
Un bon développeur sait écrire du code propre. Un bon architecte sait identifier le code qui n'aurait jamais dû être écrit.
Ce n'est pas la même compétence. La première s'apprend en codant. La seconde s'apprend en observant des bases de code vieillissantes, en posant la question "qui utilise vraiment ça ?" pour chaque module, et en acceptant qu'une bonne partie des réponses soit "personne".
La complexité s'accumule silencieusement, PR après PR. La simplicité, elle, se défend activement - à chaque revue de code, à chaque décision d'architecture, à chaque "on en aura besoin plus tard" qu'on refuse de valider sans preuve.
Pourquoi supprimer du code fait peur
Supprimer du code touche à quelque chose d'irrationnel dans une équipe technique. Trois raisons reviennent systématiquement :
- La peur de casser quelque chose d'invisible. Sans documentation claire ni observabilité fiable sur l'usage réel des features, personne ne peut garantir à 100% qu'une suppression est sans risque.
- Le sentiment de gâcher du travail. Ce code a été pensé, écrit, testé. Le supprimer donne l'impression d'effacer un effort passé, même quand cet effort ne sert plus à rien aujourd'hui.
- L'absence de valorisation. Une PR qui ajoute une feature se voit en démo. Une PR qui supprime 2000 lignes de code mort ne se voit dans aucune métrique produit - alors qu'elle a souvent plus d'impact sur la vélocité de l'équipe qu'une nouvelle feature.
C'est pour ça que ce refactoring-là ne se déclenche jamais tout seul. Il faut quelqu'un qui pose explicitement la question, et qui assume la décision.
Comment j'identifie le code à supprimer en mission
Quand j'interviens comme CTO hands-on sur une base de code existante, l'audit de dette technique passe systématiquement par cette grille :
- Mesurer l'usage réel avant de juger le code. Logs, analytics, feature flags : je cherche des preuves d'utilisation avant de me fier à l'intuition de l'équipe sur ce qui sert ou non.
- Tracer les dépendances non utilisées. Des outils comme
depcheckouknipremontent en quelques minutes les packages jamais importés en pratique - un gain rapide, sans risque. - Repérer les abstractions à un seul point d'implémentation. Une interface avec une seule classe qui l'implémente, un pattern factory pour un seul produit : c'est un signal fort de sur-ingénierie anticipée.
- Supprimer par petites PR, jamais en un seul gros commit. Chaque suppression doit rester réversible et facile à review, avec les tests associés retirés en même temps.
- Documenter le "pourquoi" de la suppression. Un message de commit clair évite qu'une feature "réapparaisse" six mois plus tard parce que personne ne se souvient pourquoi elle a disparu.
En conclusion : la suppression est une décision d'architecture
Le bon architecte n'est pas celui qui construit le système le plus sophistiqué. C'est celui qui a le courage de dire qu'une partie de ce qui existe déjà n'aurait jamais dû exister - et qui prend la responsabilité de la retirer.
Supprimer du code fait peur. C'est pourtant souvent la décision technique la plus courageuse qu'on puisse prendre, et l'une des plus rentables : moins de code à maintenir, moins de surface d'attaque, moins de temps de build, et une équipe qui navigue plus vite dans une base de code qu'elle comprend enfin entièrement.
P.S. : Si votre équipe hésite à supprimer une feature depuis plus de six mois "au cas où quelqu'un en aurait besoin", c'est probablement le signal qu'un audit de dette technique s'impose.
FAQ : supprimer du code mort et réduire la dette technique
Pourquoi supprimer du code rend-il une application plus rapide ?
Moins de code, c'est moins de logique à exécuter, moins de dépendances à charger, un bundle plus léger et des temps de build plus courts. Le code mort continue souvent de s'exécuter en arrière-plan (imports, initialisations, checks conditionnels) même sans être utilisé par les utilisateurs finaux, ce qui pèse directement sur les performances.
Comment identifier le code mort dans une base de code existante ?
En croisant plusieurs sources : les logs d'usage réel des fonctionnalités, des outils d'analyse statique comme depcheck ou knip pour les dépendances non importées, et une revue manuelle des abstractions qui n'ont qu'un seul point d'implémentation. L'intuition de l'équipe seule ne suffit pas - il faut des preuves d'usage avant de supprimer.
Faut-il un audit technique complet avant de supprimer du code ?
Pas nécessairement un audit complet, mais un minimum de mesure de l'usage réel est indispensable pour éviter de casser une fonctionnalité encore utilisée par un segment de clients. Un audit ciblé sur les dépendances, les features à faible usage et les abstractions sur-dimensionnées suffit souvent à démarrer.
Supprimer du code mort est-il risqué pour la stabilité d'une application ?
Le risque existe si la suppression se fait en un seul gros commit sans tests ni validation. Il diminue fortement si le travail est fait par petites PR réversibles, avec les tests associés retirés en même temps et une documentation claire du pourquoi de chaque suppression.
Benjamin Raimond
CTO hands-on : j'architecture, je code, je structure l'équipe technique. Je transforme des objectifs business en solutions robustes et durables pour les startups et PME.
En savoir plus →