Les indispensables d’un projet frontend - Limiter la logique dans les composants

le 17/01/2019 par Pierre Trollé
Tags: Software Engineering

Voici plusieurs années que je travaille sur des projets informatiques en tant que développeur fullstack spécialisé dans le domaine du frontend. Je vous propose dans cette série d’articles de découvrir les bonnes pratiques qui facilitent la vie au quotidien des équipes.

Nota Bene : Cet article est plus spécifiquement rédigé pour des architectures frontend avec une approche composant. Avec les autres architectures, on peut également retrouver ce concept de séparation logique métier/vue (par exemple, pas de logique dans un contrôleur).

Le problème

Au fil des projets frontend, les composants deviennent de plus en plus complexes. Les fonctionnalités requièrent éventuellement des récupérations de données du backend, des formatages, des tris, des filtres, des calculs, des validations, des transmissions entre les composants… Voici l’essentiel de ce que j’appelle la logique frontend.

Logique frontend : Toute la logique qui découle des règles de l’interface client.

Lorsqu’un composant possède une grosse part de logique, il est compliqué pour les développeurs de comprendre le fonctionnement de ce dernier. La donnée est récupérée à un endroit, puis elle est formatée, puis filtrée, triée, recalculée, mais que se passe-t-il si la requête réseau est soumis à des latences ? D’ailleurs que se passe-t-il si l’utilisateur recharge sa page ou clique sur un bouton ?

  • Le cycle de vie de la donnée étant séparé à plusieurs endroits du code, il est ardu de prédire l’état de chaque donnée.
  • Le fichier du composant est immense.
  • Le composant est très difficile à tester.
  • Le but de chaque bout de code n’est pas nécessairement explicite.

Une solution

Déporter cette logique frontend dans des modules (aussi appelés services). Une autre alternative est de déplacer cette logique dans des classes métiers.

Ainsi certaines méthodes peuvent devenir indépendantes de l’affichage et plus facilement réutilisables. Elles suivent le principe de développement SRP (single responsibility principle).

Ces méthodes seront testables unitairement sans librairies de tests de composants. Isoler le code hors des composants, permet de tester de la logique sans dépendre de l’état du composant.

Mise en place

Créer des services de composants dans des fichiers Javascript (ou Typescript) et faire en sorte que les composants déportent toute la logique frontend dans ces services. Je vous propose un exemple en fin d’article.

Quand sortir la logique frontend hors des composants ?

Toujours. Chaque projet étant destiné à grossir et se complexifier, sortir la logique est un bon pattern à mettre en place à tout moment, pour éviter d’accumuler de la dette technique.

Avantages

  • Séparation des responsabilités entre l’affichage et le métier.
  • Compréhension plus claire de l’état des données.
  • Réduction de la taille des fichiers des composants.
  • Facilité de tests.

Inconvénients

  • Plus de fichiers dans la codebase. (ce qui n’est pas forcément un inconvénient)

En conclusion

Lors de votre prochain projet, ne donnez pas trop de responsabilités aux composants. Laissez les services gérer la logique frontend.

Le prochain article de la série s'attèlera à la séparation de responsabilités entre Composants Intelligents et Composants de Présentation.

Retrouvez le premier article de la série ici : Un Backend For Frontend, une API sur-mesure

Un exemple avec du code

Voici mon composant (simplifié) que je considère comme complexe. Il s’agit d’un composant qui rend une liste de commentaires.

Quels sont ses défauts ?

En analysant la méthode fetchComments(), il est notable que pour bien afficher les commentaires, le composant est obligé de :

  • utiliser axios, un client HTTP
  • connaître la variable d’environnement qui correspond à l’URL de l’API
  • spécifier le format de réponse attendu (ici JSON)
  • connaître la route exacte de l’API où sont stockés les commentaires
  • extraire la donnée des réponses HTTP qui sont visiblement stockées dans une variable ‘data’
  • réaliser la correspondance des champs pour maîtriser les données
  • trier la liste des commentaires suivant leur date de création

Code d'un composant Front

D’après le Single Responsibility Principle, le composant doit faire une seule chose et la faire bien. Autant se dire, qu’ici, il a trop de responsabilités.

Ma vision est de laisser le composant maîtriser la présentation des commentaires et de confier la récupération des commentaires à un autre service, que j’appelle comments-service.

Code d'un composant Front simplifié sans logique

Dès qu’il est monté, le composant récupère la donnée. C’est le commentsService qui lui fournit celle-ci. Puis les commentaires sont affichés dans le template. Simple !

Désormais le comments-service doit gérer la récupération de données.

Pour cela, j’utilise un api-service qui va gérer toute la partie infrastructure (axios, API_URL, extraction de la donnée dans le champ ‘data’).

Puis j’applique les fonctions de formatage et de tri, afin de fournir au composant de la donnée pure à afficher.

Code d'un service qui récupère et tri les commentaires

Et pour la route, voici mon api-service :

Code d'un service qui gère les appels vers l'API

Pour aller plus loin, il est possible de sortir les dépendances telles qu’api-service ou axios, et de les injecter directement grâce à un container de dépendances comme InversifyJS. Mais ceci est une autre histoire ;-)