paint-brush
Faire un voyage dans la migration micro-frontend - Partie 1 : Conceptionpar@isharafeev
1,323 lectures
1,323 lectures

Faire un voyage dans la migration micro-frontend - Partie 1 : Conception

par Ildar Sharafeev13m2023/07/12
Read on Terminal Reader

Trop long; Pour lire

La migration vers une architecture micro-frontend a nécessité un investissement important en termes de structure organisationnelle et de fondation opérationnelle. Il serait préférable de commencer par une architecture monolithique distribuée qui tirera plutôt parti du chargement paresseux (importations dynamiques). Il serait essentiel de diviser la base de code en différents domaines de propriété contrôlés par différentes équipes.
featured image - Faire un voyage dans la migration micro-frontend - Partie 1 : Conception
Ildar Sharafeev HackerNoon profile picture

Dans le monde numérique en évolution rapide d'aujourd'hui, où l'agilité et l'évolutivité sont cruciales, les entreprises recherchent constamment des moyens d'améliorer les performances et la maintenabilité de leurs applications Web.


Une approche populaire pour atteindre ces objectifs consiste à migrer d'une architecture monolithique vers une architecture distribuée (ou micro-frontend). Cette série d'articles, "Micro-frontend Migration Journey", partage mon expérience personnelle d'entreprendre une telle migration pendant mon séjour chez AWS.


AVIS DE NON-RESPONSABILITÉ : Avant de commencer, il est important de noter que même si cet article partage mon expérience personnelle, je ne suis pas en mesure de divulguer des détails propriétaires ou internes sur des outils, des technologies ou des processus spécifiques chez AWS ou toute autre organisation.


Je m'engage à respecter les obligations légales et à veiller à ce que cet article se concentre uniquement sur les concepts généraux et les stratégies impliqués dans le parcours de migration micro-frontend.


Le but est de fournir des idées et des leçons apprises qui peuvent être applicables dans un contexte plus large, sans divulguer aucune information confidentielle.

Motivation pour la migration

J'ai découvert les micro-interfaces (je suppose que beaucoup d'entre vous) grâce à l' article sur le blog de Martin Fowler. Il a présenté différentes manières de composer une architecture micro-frontend de manière indépendante du framework.


En approfondissant le sujet, j'ai réalisé que notre architecture monolithique existante devenait un goulot d'étranglement important pour la productivité de notre équipe et entravait les performances globales de notre application.


L'un des principaux facteurs qui m'a poussé à envisager une migration était la taille croissante du bundle de notre application.


Après avoir effectué une analyse approfondie du bundle à l'été 2020, j'ai découvert que depuis son lancement initial au début de 2019, la taille du bundle (gzippé) était passée de 450 Ko à 800 Ko (il fait presque 4 Mo analysés) - soit près du double de la taille d'origine.


Compte tenu du succès de notre service et de la prévision de sa croissance continue, il était clair que cette tendance persisterait, impactant davantage les performances et la maintenabilité de notre application.


Bien que j'étais enthousiasmé par le concept de micro-interfaces, j'ai également reconnu que nous n'étions pas encore prêts à les adopter en raison des défis spécifiques auxquels nous étions confrontés :


  1. Petite structure organisationnelle : Au moment de mon analyse, notre organisation était relativement petite et j'étais le seul ingénieur frontend à plein temps de l'équipe. La migration vers une architecture micro-frontend a nécessité un investissement important en termes de structure organisationnelle et de fondation opérationnelle.


    Il était crucial d'avoir une structure mature capable de gérer efficacement l'architecture distribuée et de refléter les dépendances entre les différents composants frontaux.


  2. Domaine d'activité limité : bien que les micro-frontends puissent être divisés en fonction de contextes limités et de capacités commerciales (en savoir plus dans l'article " Conception axée sur le domaine dans l'architecture micro-frontend" ), notre domaine d'activité principal n'était pas assez étendu pour justifier un découplage complet en plusieurs micro-interfaces. Cependant, il y avait des limites visibles au sein de l'application qu'il était logique de découper et de passer à une architecture distribuée.


Compte tenu de ces facteurs, j'ai réalisé qu'une approche graduelle était nécessaire. Plutôt qu'une migration complète vers des micro-frontends, j'ai cherché à identifier des domaines spécifiques au sein de notre application qui pourraient bénéficier d'une architecture distribuée.


Cela nous permettrait de répondre aux problèmes de performance et d'évolutivité sans perturber la structure organisationnelle globale ni compromettre l'intégrité de notre domaine d'activité. Cela nous donnerait également du temps pour développer l'équipe et observer les orientations commerciales.


Veuillez noter que si vous souhaitez résoudre le problème de performances de l'application (taille de l'ensemble) uniquement via l'architecture mciro-frontend, ce n'est peut-être pas la meilleure idée. Il serait préférable de commencer par une architecture monolithique distribuée qui tirera plutôt parti du chargement paresseux (importations dynamiques).


De plus, je pense qu'il gérerait les problèmes de taille de bundle plus gracieusement que l'architecture micro-frontend étant donné que l'architecture micro-frontend est très susceptible d'avoir du code partagé qui ne serait pas séparé en morceaux de fournisseur, et il serait intégré dans le bundle d'applications ( c'est l'un des inconvénients d'une telle architecture distribuée - vous devez avoir un compromis entre ce qu'il faut partager, quand et comment).


Cependant, l'architecture monolithique distribuée n'évoluera pas aussi bien que le micro-frontend. Lorsque votre organisation se développe rapidement, votre équipe se développera probablement au même rythme également.


Il serait essentiel de diviser la base de code en différents domaines de propriété contrôlés par différentes équipes.


Et chaque équipe devra avoir ses propres cycles de publication indépendants des autres, chaque équipe appréciera si sa base de code se concentre uniquement sur son domaine, et construira rapidement (isolation du code -> meilleure maintenabilité/moins de code à maintenir et build -> meilleure testabilité/moins de tests à maintenir et à exécuter).

Le début

Pour obtenir le soutien de la direction, j'ai élaboré un document de vision technique convaincant qui englobait une analyse complète des performances, y compris des mesures vitales pour le Web, et décrivait les différentes phases de la migration vers des interfaces distribuées.


L'une des phases intermédiaires de cette migration consistait à établir une architecture monolithique distribuée, dans laquelle plusieurs modules/widgets pouvaient être livrés de manière asynchrone via des techniques de chargement différé tout en tirant parti d'une infrastructure partagée, telle qu'un compartiment S3 et un CDN, entre le service principal et les widgets. .


Comme je l'évoquais dans mon article précédent, l'idée principale de ce type de document est de décrire l'avenir tel que vous voudriez qu'il soit une fois les objectifs atteints et les plus gros problèmes résolus. Il ne s'agit pas du plan d'exécution !


Presque 1 an plus tard, le moment était enfin venu de mettre en œuvre mon plan de migration micro-frontend. Avec l'expansion imminente dans un nouveau domaine et une équipe plus importante à notre disposition, nous étions bien équipés pour exécuter la migration.


C'était comme une occasion en or que nous ne pouvions pas nous permettre de manquer.


Après tout, rester confiné à l'architecture monolithique reviendrait à se débattre perpétuellement avec ses limites.


Le délai limité pour se développer dans un nouveau domaine a servi de catalyseur, nous propulsant vers la construction immédiate d'une architecture plus évolutive et maintenable au lieu d'avoir des itérations courtes et lentes !


Pour exécuter la migration et gérer simultanément le travail dans le nouveau domaine, nous avons divisé les équipes en deux groupes dédiés. Le travail sur les fonctionnalités, qui avait une priorité plus élevée, nécessitait plus de ressources et devait itérer à un rythme plus rapide.


Pour garantir l'intégrité et la compréhension globale du processus de migration, il était logique d'affecter une petite équipe dédiée spécifiquement responsable de la gestion de la migration.


Cependant, nous ne pouvions pas poursuivre le travail sur les fonctionnalités sans nous assurer au préalable que le concept de micro-frontend serait un succès.


Pour atténuer les risques et fournir une feuille de route claire, il était essentiel de créer un document de conception de bas niveau comprenant des estimations précises et une évaluation approfondie des risques. Ce document a servi de modèle, décrivant les étapes et les considérations nécessaires pour la migration.


L'étape cruciale de ce processus a été le développement d'une preuve de concept qui démontrerait l'intégration réussie de tous les composants conformément à la conception.


Ce jalon, nommé à juste titre le "Point de non-retour", visait à valider la faisabilité et l'efficacité de l'architecture micro-frontend.


Alors que j'étais optimiste quant au succès de la migration, il était essentiel de se préparer aux imprévus. Par conséquent, j'ai conçu un plan B, qui a agi comme une stratégie de secours au cas où le concept initial ne donnerait pas les résultats souhaités.


Cela incluait l'allocation de sept jours supplémentaires dans les estimations spécifiquement pour me faire pleurer dans l'oreiller plus quelques jours pour avoir une nouvelle entrée de module de fonctionnalité connectée au noyau via un chargement paresseux (vous vous souvenez du monolithe distribué ?).

La conception

Lors de la conception de micro-interfaces, il existe généralement 3 approches pour la composition, chacune se concentrant sur l'endroit où la résolution de l'application d'exécution a lieu. La beauté de ces approches est qu'elles ne sont pas mutuellement exclusives et peuvent être combinées selon les besoins.

Composition côté serveur

L'idée de base est de tirer parti d'un serveur proxy inverse pour diviser les bundles micro-frontend par page et effectuer un rechargement de page dur en fonction de l'URL de la route.

Avantages:

  • Simple à mettre en œuvre


Les inconvénients:

  • L'état global ne sera pas synchronisé entre les applications micro-frontend. C'était clairement un point interdit pour nous car nous avions des opérations d'arrière-plan de longue durée effectuées côté client.


    Vous pourriez dire que nous pourrions conserver un instantané de la "file d'attente" de cette opération sur le stockage local et le lire après un rechargement dur, mais pour des raisons de sécurité, nous n'avons pas été en mesure de l'implémenter.


    Ceci n'est qu'un exemple d'état global, mais voici un autre exemple de ce à quoi il peut ressembler : état des panneaux de navigation latéral (développé/réduit), messages toast, etc.


  • L'actualisation matérielle lors de la navigation dans les micro-applications n'est pas très conviviale. Il existe un moyen de mettre en cache le code HTML partagé à l'aide de service workers, mais sa maintenance est encore plus complexe.


  • Coûts opérationnels et de maintenance supplémentaires pour l'infrastructure : serveur proxy pour chaque application micro-frontend (cela peut être évité si lu directement à partir du CDN), infrastructure distincte pour déployer des dépendances communes (fournisseurs) à réutiliser par plusieurs pages, et correctement mis en cache par les navigateurs.

Composition bord-côté

Une autre approche de la composition micro-frontend est la composition côté bord, qui consiste à combiner des micro-frontends au niveau de la couche périphérique, comme un CDN. Par exemple, Amazon CloudFront prend en charge l'intégration Lambda@Edge , permettant l'utilisation d'un CDN partagé pour lire et servir le contenu micro-frontend.

Avantages:

  • Moins d'éléments d'infrastructure à entretenir : pas besoin d'avoir des serveurs proxy, des CDN distincts pour chaque micro-application


  • Mise à l'échelle pratiquement infinie à l'aide de la technologie sans serveur


  • Meilleure latence par rapport aux serveurs proxy autonomes


Les inconvénients:

  • Le temps de démarrage à froid peut devenir un problème


  • Lambda@Edge n'est pas pris en charge dans toutes les régions AWS si vous avez besoin d'une infrastructure multirégionale (isolée)

Composition côté client

La composition côté client est une autre approche de l'architecture micro-frontend qui utilise des techniques d'orchestration de micro-frontend côté client, découplées de l'implémentation du serveur.


L'acteur clé de cette architecture est une application conteneur (shell) qui a les responsabilités suivantes :


  • Répondre aux préoccupations transversales : l'application de conteneur gère la mise en page centralisée de l'application, la navigation sur le site, le pied de page et le panneau d'aide. L'intégration avec les micro-frontends qui ont des problèmes transversaux se fait via un bus d'événements, où les événements synthétiques sont envoyés et gérés dans la portée de la fenêtre globale.


  • Orchestration des micro-interfaces : l'application de conteneur détermine quel ensemble de micro-interfaces charger et quand, en fonction des exigences de l'application et des interactions de l'utilisateur.


  • Composition des dépendances globales : l'application de conteneur compose toutes les dépendances globales, telles que React, les SDK et les bibliothèques d'interface utilisateur, et les expose sous la forme d'un ensemble distinct (vendor.js) qui peut être partagé entre les micro-frontends.


L'idée générale est que chaque bundle micro-frontend produirait 2 types de fichiers de ressources :

  • {hash}/index.js : cela sert de point d'entrée pour l'application micro-frontend, le hachage représentant un identifiant unique pour l'ensemble de la construction.


    Le hachage agit comme une clé de préfixe pour chaque bundle dans le compartiment S3. Il est important de noter que plusieurs points d'entrée peuvent exister, mais le hachage reste le même pour chacun d'eux.


  • manifest.json : il s'agit d'un fichier manifeste qui contient les chemins d'accès à tous les points d'entrée de l'application micro-frontend. Ce fichier resterait toujours à la racine du compartiment S3, afin que le conteneur puisse le découvrir facilement.


    Je recommande d'activer la gestion des versions de ce fichier dans le compartiment S3 afin d'avoir une meilleure observabilité des modifications. Si vous utilisez Webpack pour construire votre projet, je recommande fortement WebpackManifestPlugin qui fait tout le gros du travail pour vous.


Le conteneur ne connaît que l'URL du domaine source de l'actif micro-frontend (origine CDN) en fonction de l'étape et de la région. Lors du chargement initial de la page, le conteneur télécharge le fichier manifeste pour chaque application micro-frontend.


Le fichier manifeste est de petite taille (~ 100 octets) pour éviter d'avoir un impact sur le temps de chargement de la page et s'adapte bien même lors de l'agrégation de plusieurs micro-interfaces dans un conteneur. Il est crucial de considérer le fichier manifeste comme immuable dans le stockage de cache du navigateur pour éviter une mise en cache agressive.


Choisir la bonne bibliothèque d'orchestration est le plus grand défi dans cette composition et sera discuté dans le chapitre suivant.

Avantages:

  • Mise en œuvre indépendante du serveur : cette approche peut être mise en œuvre sans aucune exigence de serveur spécifique, offrant une flexibilité dans la technologie backend utilisée. Comme le montre l'image ci-dessus, vous pouvez même ne pas avoir de serveur


  • Préservation de l'état global : en utilisant une application de conteneur (shell), l'état global peut être conservé lors du basculement entre les micro-interfaces. Cela garantit une expérience utilisateur transparente et évite de perdre le contexte lors des transitions.


  • Approche décentralisée : chaque micro-frontend peut décider indépendamment des données à envoyer au navigateur pour s'amorcer lui-même. L'application conteneur suit simplement un contrat bien défini, permettant une plus grande autonomie et modularité.


  • Configuration locale simple : les sources d'actifs peuvent être facilement ajustées entre les URL de production et locales en fonction des besoins de développement. Le fichier manifeste aide l'application de conteneur à découvrir et à charger les micro-interfaces requises. Les développeurs peuvent se concentrer sur l'exécution uniquement du conteneur et des micro-frontends spécifiques sur lesquels ils travaillent.


Les inconvénients:

  • Plus de sauts de réseau pour récupérer le fichier manifeste : étant donné que le conteneur doit récupérer le fichier manifeste pour chaque micro-frontend, il peut y avoir des requêtes réseau supplémentaires et une latence potentielle par rapport aux autres approches de composition. Cela peut être atténué en chargeant tous les manifestes à l'avance lors du chargement initial de la page ou en introduisant des techniques de préchargement.


  • Conformité au contrat commun : chaque micro-frontend doit adhérer à un contrat commun pour la production de builds. Cela peut être facilité par des configurations partagées et des pratiques de développement standardisées pour assurer la cohérence entre les micro-interfaces (plus d'informations à ce sujet dans les parties suivantes).

Composition hybride

Comme je l'ai mentionné plus tôt dans ce chapitre, tous ces modèles de composition peuvent être mélangés et assortis dans la même application shell. Voici un exemple de ce à quoi cela peut ressembler :

Recommandation

Je recommande de commencer par une approche homogène au début - sélectionnez un modèle de composition qui vous convient le mieux et commencez à construire l'infrastructure qui l'entoure.


Pour nous, la composition côté client était la meilleure option, mais pour l'avenir, nous avons envisagé de passer certaines régions à l'orchestration côté périphérie (en fonction de la disponibilité de Lambda@Edge).

Choisir la bibliothèque d'orchestration

Lorsqu'il s'agit d'implémenter la composition côté client dans une architecture micro-frontend, la sélection de la bonne bibliothèque d'orchestration est une décision critique.


La bibliothèque choisie jouera un rôle crucial dans la gestion du chargement dynamique et de la coordination des micro-interfaces au sein de l'application conteneur.


Plusieurs bibliothèques d'orchestration populaires existent, chacune avec ses propres forces et considérations.

Spa unique

Single-spa est une bibliothèque d'orchestration largement adoptée qui offre une approche flexible et extensible de la composition micro-frontend. Il permet aux développeurs de créer une application shell qui orchestre le chargement et le déchargement de plusieurs micro-interfaces.


Single-SPA offre un contrôle précis des événements du cycle de vie et prend en charge différents cadres et technologies.


Avantages:

  • Indépendant du framework : la bibliothèque fonctionne bien avec divers frameworks frontaux tels que React, Angular, Vue.js, etc.


  • Configuration flexible : Il offre de puissantes options de configuration pour le routage, le chargement différé et les dépendances partagées.


  • Écosystème robuste : Single-SPA possède une communauté active et un riche écosystème de plugins et d'extensions.


Les inconvénients:

  • Courbe d'apprentissage : démarrer avec un seul spa peut nécessiter un apprentissage initial et une compréhension de ses concepts et de ses API.


  • Complexité de la personnalisation : à mesure que la complexité de l'architecture micro-frontend augmente, la configuration et la gestion de l'orchestration peuvent devenir difficiles.

Qiankun

Qiankun est une puissante bibliothèque d'orchestration développée par l'équipe Ant Financial (Alibaba). Il utilise une approche HTML partielle pour la composition. Du côté de l'application micro-frontend, il produit un extrait HTML simple avec tous les points d'entrée à charger.


Après avoir consommé ce fichier HTML, le conteneur effectue toute l'orchestration et monte l'application. Dans cette configuration, le HTML partiel joue le rôle d'un fichier manifeste dont j'ai parlé dans le chapitre précédent.


Avantages:

  • Indépendant du framework : Qiankun prend en charge divers frameworks frontaux, notamment React, Vue.js, Angular, etc.


  • Intégration simplifiée : Qiankun fournit un ensemble d'API et d'outils faciles à utiliser pour créer et gérer des micro-interfaces.


  • Évolutivité et performances : Qiankun offre des mécanismes efficaces pour le sandboxing de code, l'isolation d'état et la communication entre les micro-interfaces.


Les inconvénients:

  • Conflits de dépendance : la gestion des dépendances partagées et la garantie de la compatibilité entre les micro-interfaces peuvent nécessiter une configuration et une réflexion minutieuses.


  • Courbe d'apprentissage : bien que Qiankun fournisse une documentation complète, l'adoption d'une nouvelle bibliothèque peut impliquer une courbe d'apprentissage pour votre équipe de développement.


  • Données redondantes envoyées via le réseau : l'extrait de code HTML partiel contient des données redondantes (corps, méta, balises DOCTYPE) qui doivent être envoyées via le réseau.

Fédération de modules

La fédération de modules , une fonctionnalité fournie par Webpack, a attiré l'attention et le battage médiatique dans la communauté des développeurs Web. Cette technologie permet aux développeurs de partager du code entre plusieurs applications lors de l'exécution, ce qui en fait une option attrayante pour la création de micro-interfaces.


Grâce à son intégration transparente avec Webpack et à sa flexibilité d'exécution, Module Federation est devenu un choix populaire pour la gestion et l'orchestration des micro-interfaces.


Avantages:

  • Intégration transparente avec Webpack : si vous utilisez déjà Webpack comme outil de création, l'utilisation de la fédération de modules simplifie le processus de configuration et d'intégration.


  • Flexibilité d'exécution : la fédération de modules permet le chargement et le partage dynamiques des dépendances, offrant ainsi une flexibilité dans la gestion des micro-interfaces.


Les inconvénients:

  • Prise en charge limitée du framework : bien que la fédération de modules soit compatible avec plusieurs frameworks frontaux, elle peut nécessiter une configuration supplémentaire ou des solutions de contournement pour des cas d'utilisation spécifiques.


  • Support communautaire : Module Federation est une technologie relativement nouvelle, publiée en tant que plug-in de base dans Webpack 5 (et ultérieurement rétroportée vers la v4 ). La bibliothèque Next.js est également plus récente, publiée récemment en tant que source ouverte. Comme pour tous les nouveaux outils, il peut y avoir une communauté plus petite et moins de support disponible. Il est important de tenir compte de ce facteur si vous avez des délais serrés ou si vous prévoyez de rencontrer des questions sans réponses facilement disponibles.

Conclusion

Dans cette première partie de la série "Micro-frontend Migration Journey", nous avons discuté de la motivation derrière la migration d'un monolithe Web vers une architecture distribuée et des premières mesures prises pour vendre l'idée à la direction.


Nous avons exploré l'importance d'un document de vision technique qui présentait une analyse détaillée des performances et décrivait les différentes phases de la migration.


Nous nous sommes ensuite penchés sur les considérations de conception pour les micro-frontends, en discutant de trois approches : la composition côté serveur, la composition côté périphérie et la composition côté client.


Chaque approche a ses avantages et ses inconvénients, et le choix dépend de divers facteurs tels que la synchronisation de l'état global, l'expérience client, la complexité de l'infrastructure et la mise en cache.


En outre, nous avons exploré les bibliothèques d'orchestration populaires, telles que single-spa, qiankun et Module Federation, en mettant en évidence leurs fonctionnalités, leurs avantages et leurs défis potentiels.


Rejoignez-moi dans les prochaines parties de la série alors que nous poursuivons notre voyage de migration micro-frontend, découvrant des informations plus intéressantes et précieuses en cours de route !


Publié à l'origine sur https://thesametech.com le 18 avril 2023.


Vous pouvez aussi me suivre sur Twitter , et vous connecter sur LinkedIn pour être notifié des nouveaux posts !