Challenge tes habitudes est une série de petits articles ayant pour objectif de questionner certaines de nos pratiques récurrentes parfois incomprises, mal mises en œuvre ou encore discutables.
L’impl, une star surcotée
Ici nous allons nous intéresser à une “bonne” pratique que j’ai croisée dans toutes mes missions de développeur sans exception. Cette pratique consiste à créer systématiquement des interfaces pour les services et, trop souvent, à les suffixer avec: celui qu’on ne présente plus – catégorie
Alors même que faire des interfaces en toutes occasions pour augmenter le découplage entre différentes fonctionnalités est de prime abord un geste louable, je me suis retrouvé confronté au même pattern qui revenait systématiquement sur tous les projets que j’ai rencontrés, à savoir : toujours une interface MonUltraSpecifiqueService et son unique implémentation MonUltraSpecifiqueServiceImpl dans le même package ou presque.
Je sais ! Moi aussi quand j’ai commencé à développer, c’est l’une des premières choses que j’ai apprises, ainsi que de commenter toutes mes classes et d’avoir une couverture de code au taquet ! Je sais que c’est difficile, mais voici la dure vérité : tu n’as pas besoin des Impl…
I know, but you will… Let me tell you why…
L’utilisation d’une interface tu questionneras…
La première raison est que tu n’as pas nécessairement besoin de faire une interface pour garder ta base de code évolutive. En fait lorsque tu as appris la POO, et que tu as découvert la magie des interfaces, tu as pu avoir l’impression que des services sans interface impliquait forcément un fort couplage et par voie de conséquence une non-évolutivité de notre base de code. FAUX ! Tout ce que tu as besoin de faire est de bien encapsuler ta classe d’implémentation et de ne pas l’instancier directement dans les classes consommatrices de sa fonctionnalité (IOC my friend).
Tu n’auras probablement jamais d’autres implémentations pour cette interface. Je dis bien probablement, car les gros projets de librairies avec des api de la mort qui tuent et qui voient pulluler masse d’implémentations, c’est clairement pas représentatif de ce qu’on fait le plus dans l’informatique de gestion (YAGNI my friend).
L’expressivité du code tu privilégieras…
La deuxième raison est que l’Impl, est la plupart du temps, aussi expressive que Hodor, et encore c’est pas cool pour lui.
I’Impl peut néanmoins parfois servir de marqueur pour savoir quels niveaux d’extension, dans le cadre de chaînes d’héritages interminables, sont effectivement instanciés. C’est une situation que je conseille d’éviter (si c’est déjà là faut faire avec !) au profit de design patterns de structure comme le Decorator pour préserver l’expressivité et l’évolutivité du code avec un surcoût quasi nul dans un contexte IOC. Donc si tu veux passer maître jedi dans expressivité de ton code et ainsi valider la deuxième règle du simple design, laisse tomber l’Impl.
Par ailleurs si tu galères à nommer ton implémentation après avoir fait ton interface MonUltraSpecifiqueService, ça peut être le signe qu’aujourd’hui tu n’as pas besoin d’une interface. Dans ce cas contente toi d’une implémentation MonUltraSpecifiqueService et puis c’est tout ! (KISS my friend).
Si demain il s’avère que d’autres implémentations ont besoin de voir le jour, tu pourras utiliser le nom MonUltraSpecifiqueService (qui n’était peut-être pas si spécifique que ça en fin de compte) pour ton interface et ainsi ne casser aucune dépendance. Quant à tes implémentations, les nommer n’en sera que plus simple puisque tu connaîtras leurs spécificités à chacune, lesquelles pourront te servir de marqueurs dans tes noms de classes ! Au final avec ou sans interface Impl, en cas d’évolution de tes services, les modifications à effectuer seront les mêmes pour les classes consommatrices : modifier le fournisseur d’instance (conteneur IOC, Factory, …).
Le mot de la fin…
Prudence tout de même petit scarabée, je ne dis pas qu’il faut foncer purger toutes tes interfaces à coup de Mafuba. Il y a un tas de bonnes raisons d’utiliser ces interfaces du diable (contextes d’apis, de modules, …), seulement il est souhaitable de ne pas rendre leur utilisation systématique, et d’apporter de l’information dans le nommage de leurs implémentations !
Enfin je pourrais t’expliquer pourquoi tu peux avoir la sensation que j’ai violé certaines règles du SOLID (peut-être l’ai-je fait…) mais ça ne serait plus un mini-article. Je propose donc qu’on traite le sujet ultérieurement !
Cheers !
Marvin Gilly – El Rhum Adorator