Retour sur la mise en place d'une application Angular 8


Introduction

Il y a deux types d’applications web : celles disposant d’une architecture Fullstack et les autres.

Dans ma courte carrière de développeur web, j’ai eu l’occasion de toucher à différents frameworks, que ce soit Front-end ou Back-end.

Je vais ici me focaliser sur mon expérience en tant que développeur Front-end, plus particulièrement sur la mise en place d’une application Angular 8 chez l’un de nos clients.

Je tiens à préciser que cet article est bien un retour d’expérience et non un tutoriel, il n’y aura donc pas de step by step sur la création des divers composants ou autres mais bien une présentation de l’approche que nous avons eue par rapport aux besoins du client.

Avant d'entrer dans le vif du sujet, je vais tâcher de vous présenter Angular.


Qu’est-ce que Angular ?

Avant de présenter Angular, il convient de présenter les applications Front-end en général.

Que fait une application Front-end ?

Concrètement, elle va permettre d’exposer des pages webs via un navigateur, notamment grâce au langage HTML et aux feuilles de style CSS.

Certaines applications permettent même la mise en place de pages dynamiques via un système de templating. On va récupérer les données auprès d’une source de données (très souvent une application de type Back-end ou directement d’une base de données) qu’on va injecter dans le HTML via un système de templates.

Mais je ne vous apprends rien.

Angular permet donc la mise en place de pages dynamiques et va même bien plus loin que ça.

Il s’agit d’un framework JavaScript, encore un. Mais s’il a su s’imposer, avec React et Vue.js, comme l’un des plus utilisés c’est notamment grâce à son architecture de type MVC orientée services et l’intégration native du TypeScript et de la librairie RxJS.

Le TypeScript nous permet d’avoir une surcouche JavaScript orientée objet et facilite grandement la communication avec une API orientée objet (notamment Java). Cela apporte néanmoins une rigidité du fait que le modèle sera strict, en comparaison avec React qui de manière native n’embarque pas TypeScript et permet donc la gestion d’objets JSON sans structure stricte.

L’utilisation de la librairie RxJS permettant la mise en place d’appels asynchrones rend donc Angular très complet dans la création d’une application dynamique et orientée services, notamment grâce à l’injection de dépendances similaire aux beans que l’on peut voir dans Spring Boot.

Grâce à RxJS, il devient aisé de faire des appels asynchrones à une application Back-end, ou même entre les composants Angular eux-mêmes.

Mais passons maintenant au vif du sujet et parlons du besoin qu’avait notre client.


Le besoin du client

Le client, pour lequel nous avons développé cette application, avait un besoin très précis :

  • La possibilité de créer des objets à partir d’une carte interactive afin d’appliquer des algorithmes de machine learning sur ces objets
  • La possibilité de visualiser les résultats de ces algorithmes sur un dashboard interactif

Pour le premier besoin, il s’agirait donc d’avoir une carte interactive avec possibilité de délimiter des zones, et un formulaire qui ajouterait de la méta-donnée à ces zones avant de les enregistrer en base, ce qui aura pour effet de déclencher les algorithmes de machine learning sélectionnés.

Pour le second besoin, on devrait pouvoir sélectionner un objet créé via la carte et pouvoir afficher les résultats des algorithmes de machine learning de manière interactive et en fonction d’une date, à la manière de Kibana ou de Tableau.

Voyons maintenant comment ce besoin a été matérialisé par mes collègues Ippon et moi.


Notre solution

Présentation générale de notre solution

Pourquoi Angular 8 ?

La robustesse d’Angular, notamment grâce à la manière dont sont gérés les composants et les services, permet d’avoir une application facilement maintenable et remplissant beaucoup de critères dans les besoins du client. De plus, TypeScript apporte la rigueur nécessaire pour interagir avec l’API Spring Boot.

Nous avions donc mis en place une API faisant l’interface entre cette application front et la base de données utilisée.

L’API étant développée avec le framework Spring Boot et la librairie Webflux/RxJava, Angular était tout indiqué grâce à la présence native de RxJS au sein du framework.

Structure générale de l'application

Afin de respecter les besoins du client, et grâce aux designs de notre UX designer, nous avons pu arriver à un résultat plutôt sobre et non moins fonctionnellement adapté aux besoins du client.

Nous ne nous pencherons pas sur l’authentification car elle était gérée par un service extérieur à l’application.

Mais passons au design tant attendu de cette application avec des schémas afin de ne pas montrer de captures de l’application du client, pour des soucis de confidentialité.

Architecture des composants Angular

Dans une application front, que ce soit React ou Angular, nous allons avoir envie de créer des composants et de les réutiliser autant que possible afin de ne pas avoir de gros composants monolithiques lourds et entraînant forcément de la duplication de code.

Nous avons donc opté pour un découpage en composants tel que décrit ci-après :

La carte interactive et le formulaire

Cette page est relativement simple : à gauche un formulaire des plus classiques, à droite une carte interactive permettant de délimiter des zones. Je ne rentrerai pas en détail sur le choix de la carte en tant que telle car nous avons utilisé la librairie présente dans les autres applications du client.

Le formulaire va avoir plusieurs étapes successives : zone principale, sous-zones, définition des méta-données comme le nom de l’objet ou les algorithmes à appliquer afin de générer les résultats associés.

Le format de la sidebar étant le même sur les 3 écrans de l’application, le CSS peut être réutilisé dans les 2 autres sidebars.

A l’issue du parcours utilisateur, un objet est créé et inséré en base via un appel à l’API Java. Les algorithmes de machine learning sont ensuite déclenchés afin de générer les résultats.

La liste des objets

Nous avions besoin d’une page pour afficher la liste des objets qui avaient été créés. Nous avons donc opté dans un premier temps pour la structure suivante :

En revanche, une bonne partie de l’écran n’est pas utilisée, c’est pourquoi bien plus tard cette partie sera bougée dans la sidebar de la homepage.

La structure est très simple, une sidebar avec une liste de catégories pouvant se déployer en une autre liste sous-jacente des objets contenus dans cette catégorie.

Cliquer sur un objet nous amène directement sur le dashboard présentant les résultats de cet objet.

Le dashboard

Pour le dashboard, il nous fallait une page laissant une place relative pour les cards, afin de pouvoir en afficher le plus possible sans avoir besoin de scroll.

Nous avons donc mis en place la structure telle que décrite ici :

Pour la partie visualisation des résultats d’algorithmes, nous avons opté pour une sidebar sur la gauche permettant la sélection des résultats à afficher.

Ces derniers seront affichés dans des cards dans la partie droite de l’écran.

Ces cards contiendront :

  • le nom de la source de données
  • le nom de l’algorithme appliqué sur l’objet
  • un menu permettant diverses actions comme un zoom ou le téléchargement des résultats au format PNG ou GIF pour les images et CSV pour les graphiques
  • le résultat sous forme de graphique, d’image ou même de heatmap

Comme vous pouvez le voir, la structure du dashboard laisse beaucoup de place aux cards contenant les résultats, tout en permettant une lisibilité des algorithmes appliqués sur l’objet sélectionné et un déroulement des dates propres aux résultats de cet objet.

Dans la sidebar, nous avons le même type de composant que dans la liste, une liste déroulante mais cette fois avec une checkbox auprès des éléments de la liste déroulante.

Chaque résultat étant associé à une date, le composant timeline va permettre de parcourir les résultats par date disponible.

Ainsi s’achève la présentation de la partie composants, je vais maintenant parler de la partie services qui fait office de Back-end à notre application Front-end.


Interaction entre composants et services

Dans une application Angular, l’injection de dépendances va nous permettre de créer ce qu’on appelle des services. Ces services seront instanciés au lancement de l’application et pourront être importés dans nos composants via le constructeur de ces derniers.

Il y aura donc plusieurs types de services : ceux permettant de communiquer avec des composants extérieurs à l’application, notamment l’application Spring Boot qui va faire les échanges avec la base de données, et ceux permettant l’interaction entre les différents composants.

Nous allons nous focaliser sur ces derniers, les premiers étant plutôt classiques et faisant des actions qui sortent de l’application.

Les services internes aux composants

Au sein de notre application, nous avions divers services permettant la communication inter-composants ou encore inter-pages.

Par exemple, nous avions un service permettant de lier la carte et le formulaire, afin de récupérer les coordonnées de l’objet dessiné et de l’intégrer à l’objet qui serait entré en base ultérieurement.

Ou encore un service permettant de gérer la timeline du dashboard. Permettant ainsi de passer les dates, vers l’avant ou l’arrière, de récupérer la date courante ou les dates disponibles de tel ou tel résultat.

Ces services ont été possibles grâce à un objet propre à la librairie RxJS, les Subjects. Ces derniers permettent d’envoyer une notification aux composants qui vont y souscrire.

Le comportement est tel que :

  • On souscrit au Subject dans un composant
  • On appelle la fonction next du Subject dans un autre
  • Le premier va recevoir une notification comme quoi le Subject a été déclenché.

Dans la famille des Subjects, on a notamment l’objet BehaviorSubject qui permet même d’embarquer une valeur. Ce dernier nous a notamment été utile pour embarquer la date courante de la timeline.

Un autre exemple serait le service permettant de générer les cards du dashboard. Ce service va prendre en entrée un résultat récupéré de l’application Spring Boot et va en générer la card, ajouter ses dates à la timeline et déterminer de quel type de card on devra disposer (image, graphique, heatmap...).

Ce service nous a permis une grande généricité des résultats afin de rendre les cards identiques à l’exception du composant à l’intérieur de ces dernières.

Nous avions donc une architecture orientée services au sein même d’une application Front-end. Ce qui a permis de faire beaucoup de choses qui n’auraient pas été possibles dans une application plus classique.


Conclusion

Après un long été de développement, l’application a enfin pu prendre forme à la grande satisfaction de notre client.

Ce fut un exercice très motivant et intéressant, et je remercie mes chers collègues Ippon pour l’entraide lors de cette mise en place ainsi que notre client pour la confiance qu’il nous a accordée.

Malgré l’aspect plutôt lourd d’une application Angular, elle est néanmoins robuste et la gestion de l’asynchrone native à Angular est un gros plus. Les diverses librairies qu’Angular met à disposition permettent de solutionner rapidement un grand nombre de problèmes courants.

Il convient néanmoins de dire que je n'ai pas une connaissance exclusive du développement front-end, et que bon nombre de ces fonctionnalités sont sûrement possibles dans d’autres frameworks qu'Angular 8. L'idée de cet article est bien de partager ce que j'ai pu apprendre. En espérant que cela aura été enrichissant !