Aujourd’hui, le développement front-end repose presque entièrement sur les composants. Dès qu’il est question d’interfaces riches en interactions, cet outil devient si puissant qu’il s’impose comme la solution incontournable.
Bien que le concept soit si répandu, le périmètre des composants reste ambiguë, au point que chacun finit par en avoir sa propre interprétation. En réalité, c’est précisément parce que cette définition est floue qu’ils sont autant utilisés. Chacun peut les adapter comme il le souhaite, ce qui explique à la fois leurs succès et l’absence d’un véritable consensus.
Vous comprendrez donc qu’il n’est pas question ici de fournir une recette magique ni de détailler une implémentation figée. L’objectif est plutôt de se concentrer sur les questions à se poser lorsqu’on se retrouve face à une situation de création de composant. Un système complexe n’est rien d’autre que l’accumulation de systèmes simples. C’est exactement ce que sont les composants : notre application est un système complexe résultant de l’agrégation de composants.
Cet article est la première pièce d’une série visant à expliquer les bases d’une architecture front-end cohérente. On va s’attaquer à deux concepts fondamentaux qui, une fois bien compris, changent durablement la façon dont on découpe une interface : le contexte et la responsabilité d’un composant
Un composant a un contexte
Le context d’un composant c’est l’ensemble des informations “implicites” d’un composant. Son naming, sa place dans l’arborescence, les outils utilisés, la propretés du code etc …
Pour illustrer l’importance de ce concept analysons deux idées ou notre notion de contexte brille.
Générique et réutilisable = qualité
Oubliez l’idée qu’un composant doit être générique. Dans la majorité des cas, vouloir le rendre générique fera perdre de la valeur à votre code. Un composant a une identité propre, qui dépend du projet, du design et du besoin auquel il répond.
Oubliez aussi l’idée qu’un composant doit forcément être réutilisable. Il n’y a aucun problème à créer un composant que vous n’utiliserez qu’une seule fois. Ce composant isolera une logique ou un comportement complexe du reste de l’application.
Mais le point le plus important c’est de comprendre la différence entre générique et réutilisable qui est souvent mal comprise.
Un élément générique vise à être utilisable dans tous les contextes: il ne répond à aucun besoin précis et reste volontairement abstrait pour couvrir un maximum de situations.
Générique ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ Réutilisable
Répond à un besoin précis ✗ ✓
Utilisable dans tous les contextes ✓ ✗
Facile à maintenir ✗ ✓
Exemples <Button>,<Modal> <ArticleCard>,<NavBar>
La confusion vient souvent du fait qu’un élément réutilisable peut être employé plusieurs fois, ce qui donne l’impression qu’il est générique. Pourtant, vouloir transformer un élément réutilisable en élément générique accroit la complexité, dilue son objectif et le rend plus difficile à maintenir.
Dans la majeure partie du temps, un composant s’inscrit dans un contexte d’utilisation. Ce contexte est donc l’ensemble des informations qui entourent la tâche technique que vous devez réaliser. Ces informations sont importantes, car elles donnent du sens et de la lisibilité à votre code. L’objectif est d’ancrer notre composant dans une réalité et de faire apparaître le plus d’informations utiles, c’est le contexte.
Un composant trop spécifique créé une dette technique
On pense souvent, que contextualiser un composant augmente les coûts potentiels en cas de changement du besoin.
En effet comme le composant est spécialisé pour un besoin A, si le besoin change, on imagine qu’il faudra tout reprendre. Pourtant, cette logique n’est pas toujours la bonne. Illustrons avec un exemple.
Prenons une entreprise qui maintient un site d’article de blog. Ils ont recruté une équipe de développeurs et se lance dans le développement du site.

Besoin A : notre site web a besoin d’une barre de navigation horizontale en haut de la page.
Julien, développeur junior, veut bien faire et crée un composant “navigation-bar”. À ce composant, Julien ajoute une entrée isHorizontal pour pouvoir changer l’orientation de la barre. En effet, julien souhaite que sa barre puisse être réutilisée à travers le projets. Fier de cette fonctionnalité, il merge son code. À partir de ce jour, chaque développeur qui modifie la barre de navigation devient responsable de maintenir une fonctionnalité qui n’apporte en réalité aucune valeur au projet.
Un an plus tard, l’application évolue vers un style plus orienté dashboard. On demande alors de remplacer la nav-bar par un side-menu. La fonctionnalité isHorizontal existant déjà, il est proposé de conserver le composant navigation-bar et de le mettre en isHorizontal = false.

Besoin B : notre site web a besoin d’un side-menu sur la gauche.
Commence alors un chantier pour transformer la nav-bar en side-menu. Oui, la fonctionnalité était présente et maintenue fonctionnellement, mais entre-temps les normes du projet ont évolué, le framework a changé de version et le design n’est plus vraiment le même. Il faut donc faire du neuf avec du vieux.
Résultat : certaines balises HTML ne sont plus les bonnes, des classes CSS deviennent orphelines et une partie de la logique liée aux dropdowns est conservée inutilement.
Maintenant, si Julien n’avait pas essayé d’être plus générique que se serait-il passé ?
Concrètement, Julien aurait pu appeler son composant top-nav-bar, sans paramètre isHorizontal. Quand le besoin d'un side-menu apparaît, la réponse naturelle devient : créer un side-menu. Pas bidouiller top-nav-bar. Les deux composants coexistent, chacun avec son rôle, et supprimer l'un n'impacte pas l'autre.
Empêcher un composant de se complexifier permet d’assurer qu’il reste manipulable. Plus un composant est clair dans son intention, plus il sera facile à faire évoluer. Le contexte aide ainsi à prendre de meilleures décisions architecturale.
Un composant a une responsabilité
La responsabilité est le deuxième pilier de cette réflexion. Un composant représente une unité cohérente de savoir et de comportement. Autrement dit, il doit pouvoir exister seul et remplir une mission claire. Vous connaissez sûrement le principe SRP (Single Responsibility Principle) : c’est exactement la même idée. Un composant doit répondre à un seul besoin.
Sur ce même site, on demande à Julien de créer des “cards” pour afficher des articles. Elles doivent contenir un titre, une image et un bouton pour lire l’article. Julien s’en sort bien et crée un composant “card”.
Deux mois plus tard, un nouveau type d’article apparaît. Ces articles ont une bannière et une icône. Pour les différencier on ajoute aussi un système de tags. Julien met donc à jour son composant “card”, désormais responsable d’afficher plusieurs types d’articles.
Six mois plus tard, l’entreprise se lance dans les podcasts. Ils ont besoin d’une card, similaire visuellement, mais cette fois la card doit permettre de lire un fichier audio.
Julien prend alors la décision de réutiliser son composant card pour afficher aussi les podcasts. Et c’est là que les ennuis commencent : les responsabilités se mélangent et le contexte disparaît. On ajoute des fonctionnalités à un composant existant, et petit à petit, il mute.
Très vite, il dépasse les 500 lignes et devient une source d’erreurs infinie. Corriger un bug sur les articles crée un bug sur les podcasts. Plus personne ne comprend quelles fonctionnalités appartiennent à quoi, et le composant devient un amas illisible.
ouai elle fait plein de chose cette card
La meilleure manière d’éviter cette situation est de prévenir plutôt que guérir. Cas classique où la responsabilité n’a pas été respecté. Dans notre exemple, il est plus intuitif de dire qu’un podcast n’est pas un article, plutôt que de dire qu’un podcast n’a pas sa place dans une “card”. Ainsi, on aurait préféré avoir une “ArticleCard” qui continue de gérer les articles, et un nouveau composant PodcastCard pour afficher les podcasts.
Contexte et responsabilité sont liés mais distincts. Le contexte répond à la question où se trouve le composant et quel est sa raison d’exister ? La responsabilité répond à qu’est-ce qu’il fait ?
Un composant peut avoir un contexte clair (article-card) mais plusieurs responsabilités si cette card gère à la fois l'affichage, le tracking analytique et la lecture audio, elle a un problème de responsabilité.
Inversement, un composant card générique peut n'avoir qu'une seule responsabilité : afficher du contenu mais sans contexte, personne ne sait quel contenu, pour qui, et dans quel cadre.
Alors, un bon composant ? C’est simplement un composant qu’on peut lire, modifier et supprimer sans appréhension. Je l’ouvre et je sais directement ce que je peu faire avec. Il vie dans le temps et donne des informations sur son identité. Pour ceci, il est ancré dans un contexte : son nom, son emplacement, son typage doivent refléter le besoin auquel il répond. Il n’a qu’une responsabilité : une mission claire, qu’on peut énoncer en une phrase.
Évidement ces deux critères ne sont pas des règles rigides. Ce sont des questions à se poser. Est-ce que ce composant répond à un besoin précis ? Est-ce qu’il fait une seule chose ? Si oui, vous êtes probablement sur la bonne voie.
Dans le prochain article, on ira plus loin en parlant du pattern container/presentationnal. Avoir de bons composants ne suffit pas, il faut aussi savoir les organiser entre eux.






Top comments (0)