Magasin de données
Présentation du pattern Flux/Redux
Les applications graphiques créées avec des technologies front-end sont généralement amenées à grossir rapidement. En effet, une seule application graphique concentre souvent à elle seule l’appel à plusieurs services back-end, a fortiori dans le cas d’une architecture de microservices. Bien que des solutions existent pour éviter la multiplication des points d’accès, l’application graphique devient tout de même de moins en moins modulaire.
De ce fait, il y a à la fois une multiplication d’écrans et une multiplication des données manipulées. Souvent, un écran affiche une donnée que l’écran précédent a lui aussi affichée (par exemple, les informations d’un enregistrement provenant d’une liste, qui elle-même affichait une partie des informations). Dans ce cas précis, contacter systématiquement l’API n’est pas une solution viable, car cela crée une surcharge serveur importante, qui peut être évitée. L’application front-end doit rester le plus autonome possible et disposer d’un système de cache.
Le pattern Flux permet de répondre à cette problématique. Initialement, cette solution a été proposée par les ingénieurs de Facebook, qui l’ont concrétisée avec la brique technique appelée Redux, désormais connue. Le principe est assez simple.
L’application dispose d’un magasin de données central, appelé le store, qui contient les informations importantes de l’application. Ce magasin de données mute à chaque fois qu’une donnée est changée (ajout, modification ou suppression), afin de refléter systématiquement l’état actuel de la totalité de l’application. De plus, ces mutations créant chaque fois un nouvel état, il est possible d’observer les différences entre deux états et de tracer ce qu’il s’est passé.
La centralisation permet également à tous les écrans de se brancher sur une source de données unique, et non d’utiliser chacun leur propre source, ce qui pourrait créer...
Implémentation du store
On comprend assez facilement que la logique du store devient de fait essentielle et centrale dans notre application, c’est pourquoi il est vivement conseillé de la déplacer dans un composant à part.
1. Création du store
Afin de partir sur de bonnes bases, nous allons commencer par créer notre librairie .NET 5 qui contiendra les actions, les reducers et le store de notre application. Cela peut se faire à l’aide de notre IDE favori, ou de la ligne de commande suivante :
dotnet new classlib -n BlazorRedux
Même si un store reste la seule source de vérité, il est possible de créer un store global pour l’application, lui-même découpé, ou de créer un store par logique (en suivant un service donné par exemple). Dans le cadre de cet exemple, nous allons créer un store global.
a. Classe contenant l’état de l’application
Comme nous l’avons vu précédemment, le store doit être immuable, ce qui se traduit par un état qui ne peut être altéré après sa construction. Si on désire stocker les données du projet d’exemple Blazor, il nous faut donc deux propriétés : la valeur actuelle du compteur et la liste des données météo. Notre classe qui sert d’état ressemble donc à ceci :
public class AppState
{
public int CurrentCount { get; }
public IEnumerable<WeatherForecast> Forecasts { get; }
public AppState(
int currentCount,
IEnumerable<WeatherForecast> forecasts)
{
if(currentCount < 0)
{
throw new ArgumentException("Current count < 0",
nameof(currentCount));
}
CurrentCount = currentCount;
Forecasts = forecasts ?? throw new
ArgumentNullException(nameof(forecasts));
}
}
Le code précédent...
Débogage du store
Notre store évolue dans le temps, passant d’un état à l’autre. Lors de l’élaboration d’une application, il peut être pertinent d’utiliser des outils permettant de tracer ces changements, mais aussi de comparer les versions de l’état.
Des outils de débogage ont été créés à cet effet, pour Redux notamment, et peuvent être utilisés par Fluxor. Voyons comment les utiliser sur notre implémentation pour permettre le suivi.
1. Installation de l’extension Redux DevTools
Tout d’abord, l’outil principal dans le navigateur permettant de traquer les changements d’état ne fonctionne que sur un navigateur qui utilise Chromium comme base (donc Chrome ou Edge Chromium) ou sur Firefox. L’extension en question s’appelle Redux DevTools. Il nous faut procéder à l’installation de cette extension sur notre navigateur de travail. Redux DevTools est normalement visible dans le coin supérieur droit sous la forme d’une icône qui ressemble à un radar :
Icône de l’extension Redux DevTools sous Google Chrome
Cette icône prend des couleurs et offre des fonctionnalités avancées dès lors que l’extension détecte un lien avec un store, ce que nous allons configurer.
Si on ouvre notre application avec l’extension installée, l’icône ne réagit pas. En effet, Fluxor ne communique pas avec l’extension si on ne le configure pas à cet effet. Il faut...
Nouveautés .NET 5
Il n’y a pas de nouveauté réellement liée à .NET 5 dans ce qui est exploré dans ce chapitre, exception faite d’une amélioration du langage C#. En effet, dans sa version 9, C# offre une nouvelle façon de décrire une classe, qui est plus efficiente (moins de code à écrire) et apporte également une notion d’immuabilité intéressante.
Nous avons vu précédemment que les actions ainsi que les différents états doivent être immuables, ce qui veut dire que les données doivent être définies à la construction, sans possibilité d’altération ultérieure.
C# 9 introduit un nouveau mot-clé pour les propriétés : init. Quand une propriété est définie avec init, la seule possibilité est qu’elle soit affectée dans le constructeur. Même s’il était possible d’avoir un comportement qui s’en approche en mettant uniquement l’accesseur get sur une propriété, il n’était pas possible d’utiliser l’object initializer (fonctionnalité permettant de définir les propriétés dès la création) à cet effet.
Considérons la classe suivante :
public class Employee
{
...
Exercice
Maintenant que nous connaissons le principe du store et les différents mécanismes qui sont liés à ce dernier, il est temps de modifier notre application fil rouge pour les appliquer.
1. Énoncé
Dans le cadre de cet exercice, il est demandé de migrer l’application de gestion de personnel que nous avons créée lors des chapitres précédents pour prendre en charge le store avec Fluxor.
Même si le périmètre fonctionnel de l’application n’est pas étendu, il est exigé d’appliquer les best practices d’un store centralisé, c’est-à-dire une séparation du store global en plusieurs états liés à des notions fonctionnelles. Ici, il est donc nécessaire d’avoir un état lié à la gestion du personnel, pour le distinguer des futures problématiques de l’application.
Finalement, il devra être possible de suivre les modifications de l’état grâce aux outils de débogage (Redux DevTools), comme nous l’avons vu au fil de ce chapitre.
2. Corrigé
Avant d’entreprendre la moindre modification sur l’application, il est nécessaire de préparer le projet en modifiant son architecture.
a. Architecture du projet
À l’instar de ce que nous avons fait au cours de ce chapitre, nous allons isoler, dans une libraire de classes, le store, les actions, les reducers et les effects pour plus de portabilité et d’extensibilité. Pour ce faire, nous allons créer notre nouvelle librairie de classes, que nous appellerons BlazorStore. Dans cette librairie, nous installerons le package contenant les éléments nécessaires pour utiliser Fluxor, à savoir Fluxor.Blazor.Web.
Ces deux opérations peuvent se faire depuis l’IDE de notre choix, ou directement depuis la ligne de commande :
dotnet new classlib -n BlazorStore
cd BlazorStore
dotnet add package Fluxor.Blazor.Web
De la même façon, il est nécessaire d’isoler nos classes de services qui pour le moment, se trouvent dans le projet Blazor de base, car notre store va devoir s’en servir. Pour éviter le mélange des responsabilités, la création d’un nouveau projet de librairie de classes...