Deezer, salle de réunion, présentation des principes SOLID devant l’équipe web. J’arrive sur le « D » : le Principle d’Inversion de Dépendance. Mes collègues interprètent ça comme : « Une interface partout, comme ça je peux changer d’implémentation sans toucher au reste du code. »
Moi le premier, à mes débuts, je pensais pareil. Chaque classe cachée derrière une interface : class DefaultRepository avec son interface Repository, class GetLicenceUseCase avec son interface GetLicenceUseCaseContract même quand une seule implémentation existait et existerait toujours
Résultat : en théorie un code imbattable en flexibilité mais difficile à lire.
Le clic qui ne mène nulle part

Tu ouvres un fichier. Tu vois licenceDataSource.getLicence(userId). Tu cliques sur getLicence pour comprendre ce qui se passe.
Android Studio t’envoie sur l’interface LicenceDataSource. Une signature. Zéro logique. Tu remontes, tu cherches l’implémentation concrète, RemoteLicenceDataSource ou LocalLicenceDataSource selon les cas. Deux clics, un aller-retour, pour lire une ligne de code.
Multiplie ça par des centaines de fichiers dans une codebase, et l’onboarding devient franchement pénible.
Ce que dit vraiment le principe d’inversion de dépendance
Le principe d’inversion de dépendance dit ceci : ta logique métier ne doit jamais dépendre directement d’un détail d’implémentation. Les deux doivent dépendre d’un contrat commun.
Concrètement : ton Repository ne doit pas savoir si les licences viennent d’une API REST ou d’une base SQLite. Il dépend de LicenceDataSource, pas du code qui parle réellement au réseau.
Le principe ne dit pas : crée une interface pour chaque classe. Il dit : protège ta logique métier des couches externes ou celles qui peuvent bouger souvent.
Cette protection sert à gérer une variation ou une frontière. Ce n’est pas un rituel à appliquer par défaut.
La règle d’inversion de dépendance que j’enseigne maintenant

Une interface se justifie. Sinon, elle ne se crée pas.
Deux cas où elle se justifie, dans mon expérience :
- Une frontière d’architecture. Par exemple dans une architecture multi-module, la couche domain ne doit pas avoir de dépendance forte à la couche data. Un
LicenceDataSourcequi parle à une API REST ou à une base SQLite est un détail d’implémentation que le domain ne doit pas connaître. Peu importe qu’il n’existe qu’une seule implémentation aujourd’hui : la frontière justifie l’interface à elle seule. - Un design pattern qui l’exige. Le Strategy pattern, par exemple. Tu as plusieurs algorithmes interchangeables (stratégie de retry, mode de tri) et le code appelant doit ignorer lequel tourne. Là, l’interface porte le contrat du pattern.
En dehors de ces deux cas : classe concrète, appel direct, code lisible.
La checklist avant de créer une interface
Deux questions, dans l’ordre :
- Suis-je à une frontière d’architecture qui doit rester stricte ? Domain qui isole data, dépendance à une librairie externe… Une seule implémentation aujourd’hui ne change rien : la frontière justifie l’interface.
- Ai-je plusieurs implémentations réelles, imposées par un design pattern comme Strategy ? Pas « peut-être un jour ». Réelles, ou sur la roadmap produit.
Une seule réponse « oui » suffit à justifier l’interface. Zéro réponse « oui » : classe concrète.
Le refacto n’est pas un échec

Six mois plus tard, une nouvelle demande produit arrive. GetLicenceUseCase, sans frontière d’architecture ni pattern au départ, doit maintenant gérer deux types de licence avec des règles différentes. Tu introduis l’interface à ce moment-là.
Ce n’est pas un raté de conception initiale. C’est le refacto qui fait son travail : répondre à un besoin réel, au moment où il existe, plutôt qu’à un besoin imaginé six mois avant qu’il n’apparaisse.
YAGNI (You Are not Gonna Need It) et refacto marchent ensemble. Le premier t’évite de coder pour un futur hypothétique. Le second te permet d’ajuster quand ce futur devient présent.
Le tableau qui résume tout
| Situation | Interface justifiée ? |
|---|---|
| Composant à la frontière de la Clean Architecture qui permet de respecter la règle des dépendances, même avec une seule implémentation | Oui |
| Implémentation d’un Design Pattern qui repose sur une abstraction | Oui |
| « On pourrait avoir besoin de changer un jour » sans frontière d’architecture ni pattern derrière | Non |
| Composant interne d’une couche de la Clean Architecture sans frontière ni pattern | Non |
Non. Il faut les réserver aux cas où elles servent une raison précise : une frontière d’architecture ou un design pattern. Le reste peut rester en classe concrète.
Non. Il impose de dépendre d’abstractions pour les éléments variables ou externes, pas de transformer chaque classe en contrat séparé.
Cherche les interfaces avec une seule implémentation, sans frontière d’architecture claire ni pattern derrière. Ce sont des candidates à la suppression.
Sanders
➡️ Rejoins la newsletter. Reçois du contenu que tu ne trouveras nulle part ailleurs.