En el acelerado mundo digital actual, donde la agilidad y la escalabilidad son cruciales, las empresas buscan constantemente formas de mejorar el rendimiento y la capacidad de mantenimiento de sus aplicaciones web.
Un enfoque popular para lograr estos objetivos es migrar de una arquitectura monolítica a una distribuida (o micro-frontend). Esta serie de artículos, "Viaje de migración de micro-frontend", comparte mi experiencia personal al realizar una migración de este tipo durante mi tiempo en AWS.
DESCARGO DE RESPONSABILIDAD : antes de comenzar, es importante tener en cuenta que, si bien este artículo comparte mi experiencia personal, no puedo divulgar ningún detalle interno o de propiedad de herramientas, tecnologías o procesos específicos en AWS ni en ninguna otra organización.
Me comprometo a respetar las obligaciones legales y garantizar que este artículo se centre únicamente en los conceptos y estrategias generales involucrados en el viaje de migración de micro-frontend.
El propósito es brindar conocimientos y lecciones aprendidas que puedan aplicarse en un contexto más amplio, sin divulgar ninguna información confidencial.
Aprendí sobre micro-frontends (supongo que muchos de ustedes) del artículo en el blog de Martin Fowler. Presentó diferentes formas de componer la arquitectura de micro-frontend de una manera independiente del marco.
A medida que profundizaba en el tema, me di cuenta de que nuestra arquitectura monolítica existente se estaba convirtiendo en un cuello de botella importante para la productividad de nuestro equipo y obstaculizaba el rendimiento general de nuestra aplicación.
Uno de los factores clave que me empujó a considerar una migración fue el aumento del tamaño del paquete de nuestra aplicación.
Después de realizar un análisis exhaustivo del paquete en el verano de 2020, descubrí que desde su lanzamiento inicial a principios de 2019, el tamaño del paquete (comprimido con gzip) había aumentado de 450 KB a 800 KB (son casi 4 MB analizados), casi el doble del tamaño original.
Teniendo en cuenta el éxito de nuestro servicio y pronosticando su crecimiento continuo, estaba claro que esta tendencia persistiría, lo que afectaría aún más el rendimiento y la mantenibilidad de nuestra aplicación.
Si bien estaba entusiasmado con el concepto de micro-frontends, también reconocí que aún no estábamos listos para adoptarlos debido a los desafíos específicos que enfrentamos:
Estructura organizativa pequeña: en el momento de mi análisis, nuestra organización era relativamente pequeña y yo era el único ingeniero frontend a tiempo completo del equipo. Migrar a una arquitectura de micro-frontend requirió una inversión significativa en términos de estructura organizacional y base operativa.
Era crucial tener una estructura madura que pudiera manejar de manera efectiva la arquitectura distribuida y reflejar las dependencias entre los diferentes componentes de la interfaz.
Dominio comercial limitado: aunque las micro-frontends se pueden dividir en función de contextos limitados y capacidades comerciales (obtenga más información en la publicación " Diseño basado en dominios en la arquitectura de micro-frontend" ), nuestro dominio comercial principal no era lo suficientemente extenso como para justificar un desacoplamiento completo en Múltiples micro-frontends. Sin embargo, había límites visibles dentro de la aplicación que tenían sentido para tallar y hacer la transición a una arquitectura distribuida.
Teniendo en cuenta estos factores, me di cuenta de que era necesario un enfoque gradual. En lugar de una migración completa a micro-frontends, mi objetivo era identificar áreas específicas dentro de nuestra aplicación que podrían beneficiarse de una arquitectura distribuida.
Esto nos permitiría abordar los problemas de rendimiento y escalabilidad sin interrumpir la estructura organizativa general ni comprometer la integridad de nuestro dominio empresarial. También nos daría algo de tiempo para hacer crecer el equipo y observar las direcciones comerciales.
Tenga en cuenta que si desea abordar el problema de rendimiento de la aplicación (tamaño del paquete) solo mediante el uso de la arquitectura mciro-frontend, puede que no sea la mejor idea. Sería mejor comenzar con una arquitectura monolítica distribuida que aproveche la carga diferida (importaciones dinámicas).
Además, creo que manejaría los problemas de tamaño del paquete con más gracia que la arquitectura de micro-frontend considerando que es muy probable que la arquitectura de micro-frontend tenga algún código compartido que no se separaría en partes del proveedor, y estaría integrado en el paquete de la aplicación ( esa es una de las desventajas de dicha arquitectura distribuida: debe tener un equilibrio entre qué compartir, cuándo y cómo).
Sin embargo, la arquitectura monolítica distribuida no escalará tan bien como la micro-frontend. Cuando su organización crece rápidamente, es probable que su equipo también crezca al mismo ritmo.
Habría una necesidad esencial de dividir el código base en diferentes áreas de propiedad controladas por diferentes equipos.
Y cada equipo deberá tener sus propios ciclos de lanzamiento que sean independientes de los demás, cada equipo apreciará si su base de código se enfoca exclusivamente en su dominio y compilará rápidamente (aislamiento de código -> mejor mantenibilidad/menos código para mantener y construir -> mejor capacidad de prueba/menos pruebas para mantener y ejecutar).
Para obtener el apoyo del liderazgo, elaboré un documento de visión técnica persuasivo que abarcaba un análisis de rendimiento integral, incluidas las métricas vitales de la web, y describía las diversas fases de la migración hacia interfaces distribuidas.
Una de las fases intermedias de esta migración fue establecer una arquitectura monolítica distribuida, en la que varios módulos/widgets podrían entregarse de forma asíncrona a través de técnicas de carga diferida mientras se aprovechaba la infraestructura compartida, como un depósito S3 y CDN, entre el servicio principal y los widgets. .
Como describí en mi artículo anterior, la idea principal de este tipo de documento es describir el futuro como te gustaría que fuera una vez que se hayan logrado los objetivos y se hayan resuelto los problemas más importantes. ¡No se trata del plan de ejecución!
Casi 1 año después, finalmente había llegado el momento de poner en práctica mi plan de migración de micro-frontend. Con la inminente expansión a un nuevo dominio y un equipo más grande a nuestra disposición, estábamos bien equipados para ejecutar la migración.
Se sentía como una oportunidad de oro que no podíamos permitirnos perder.
Después de todo, permanecer confinado a la arquitectura monolítica significaría lidiar perpetuamente con sus limitaciones.
La línea de tiempo limitada para expandirse a un nuevo dominio sirvió como catalizador, impulsándonos a construir una arquitectura más escalable y mantenible de inmediato en lugar de tener iteraciones cortas y lentas.
Para ejecutar la migración y manejar simultáneamente el trabajo en el nuevo dominio, dividimos los equipos en dos grupos dedicados. El trabajo de funciones, que tenía mayor prioridad, requería más recursos y necesitaba iterar a un ritmo más rápido.
Para garantizar la integridad y la comprensión integral del proceso de migración, tenía sentido asignar un pequeño equipo dedicado específicamente responsable de manejar la migración.
Sin embargo, no podíamos continuar con el trabajo de características sin antes asegurarnos de que el concepto de micro-frontend resultaría exitoso.
Para mitigar los riesgos y proporcionar una hoja de ruta clara, era crucial crear un documento de diseño de bajo nivel que incluyera estimaciones precisas y una evaluación de riesgos exhaustiva. Este documento sirvió como modelo, describiendo los pasos necesarios y las consideraciones para la migración.
El hito fundamental en este proceso fue el desarrollo de una prueba de concepto que demostraría la integración exitosa de todos los componentes de acuerdo con el diseño.
Este hito, acertadamente llamado "Punto sin retorno", tenía como objetivo validar la viabilidad y eficacia de la arquitectura de micro-frontend.
Si bien era optimista sobre el éxito de la migración, era esencial prepararse para las contingencias. En consecuencia, ideé un Plan B, que actuó como una estrategia de respaldo en caso de que el concepto inicial no diera los resultados deseados.
Esto incluyó la asignación de siete días adicionales en las estimaciones específicamente para tenerme llorando en la almohada más unos días para tener una nueva entrada de módulo de funciones conectada al núcleo a través de carga diferida (¿recuerdas el monolito distribuido?).
Al diseñar micro-frontends, generalmente hay 3 enfoques para la composición, cada uno de los cuales se enfoca en dónde tiene lugar la resolución de la aplicación en tiempo de ejecución. La belleza de estos enfoques es que no se excluyen mutuamente y se pueden combinar según sea necesario.
La idea básica es aprovechar un servidor proxy inverso para dividir paquetes de micro-frontend por página y realizar una recarga de página basada en la URL de la ruta.
Ventajas:
Contras:
El estado global no se sincronizará entre las aplicaciones de micro-frontend. Este fue un punto claro para nosotros porque teníamos operaciones en segundo plano de larga duración realizadas en el lado del cliente.
Podría argumentar que podríamos conservar una instantánea de la "cola" de esta operación en el almacenamiento local y leerla después de la recarga completa, pero debido a razones de seguridad, no pudimos implementar esto.
Este es solo un ejemplo de un estado global, pero aquí hay otro ejemplo de cómo puede verse: estado de los paneles de navegación lateral (expandidos/contraídos), mensajes de brindis, etc.
Otro enfoque para la composición de micro-frontend es la composición del lado del borde, que implica combinar micro-frontends en la capa del borde, como una CDN. Por ejemplo, Amazon CloudFront es compatible con la integración de Lambda@Edge , lo que permite el uso de una CDN compartida para leer y servir el contenido de micro-frontend.
Ventajas:
Contras:
La composición del lado del cliente es otro enfoque de la arquitectura de micro-frontend que utiliza técnicas de orquestación de micro-frontend del lado del cliente, desvinculadas de la implementación del servidor.
El jugador clave en esta arquitectura es una aplicación de contenedor (shell) que tiene las siguientes responsabilidades:
La idea general es que cada paquete de micro-frontend produciría 2 tipos de archivos de activos:
{hash}/index.js: sirve como punto de entrada para la aplicación de micro-frontend, con el hash representando un identificador único para toda la compilación.
El hash actúa como una clave de prefijo para cada paquete en el depósito S3. Es importante tener en cuenta que pueden existir varios puntos de entrada, pero el hash sigue siendo el mismo para todos ellos.
manifest.json: este es un archivo de manifiesto que contiene rutas a todos los puntos de entrada para la aplicación de micro-frontend. Este archivo siempre quedaría en la raíz del depósito S3, por lo que el contenedor podría descubrirlo fácilmente.
Recomiendo activar el control de versiones de este archivo en el depósito S3 para poder observar mejor los cambios. Si está utilizando Webpack para construir su proyecto, le recomiendo encarecidamente WebpackManifestPlugin , que hace todo el trabajo pesado por usted.
El contenedor solo reconoce la URL del dominio de origen del activo de micro-frontend (origen de CDN) en función de la etapa y la región. Durante la carga de la página inicial, el contenedor descarga el archivo de manifiesto para cada aplicación de micro-frontend.
El archivo de manifiesto tiene un tamaño pequeño (~100 bytes) para evitar afectar el tiempo de carga de la página y se escala bien incluso cuando se agregan múltiples micro-frontends dentro de un contenedor. Es crucial considerar el archivo de manifiesto como inmutable en el almacenamiento de caché del navegador para evitar un almacenamiento en caché agresivo.
Elegir la biblioteca de orquestación correcta es el mayor desafío en esta composición y se discutirá en el siguiente capítulo.
Ventajas:
Contras:
Como mencioné anteriormente en este capítulo, todos estos patrones de composición se pueden mezclar y combinar dentro de la misma aplicación de shell. Aquí hay un ejemplo de cómo puede verse:
Recomiendo comenzar con un enfoque homogéneo al principio: seleccione un patrón de composición que se adapte mejor a usted y comience a construir la infraestructura a su alrededor.
Para nosotros, la composición del lado del cliente era la mejor opción, pero para el futuro, consideramos cambiar algunas regiones a la orquestación del lado del borde (según la disponibilidad de Lambda@Edge).
Cuando se trata de implementar la composición del lado del cliente en una arquitectura de micro-frontend, seleccionar la biblioteca de orquestación correcta es una decisión crítica.
La biblioteca elegida jugará un papel crucial en la gestión de la carga dinámica y la coordinación de micro-frontends dentro de la aplicación contenedora.
Existen varias bibliotecas de orquestación populares, cada una con sus propias ventajas y consideraciones.
Single-spa es una biblioteca de orquestación ampliamente adoptada que proporciona un enfoque flexible y extensible para la composición de micro-frontend. Permite a los desarrolladores crear una aplicación shell que orqueste la carga y descarga de múltiples micro-frontends.
Single-SPA proporciona un control detallado sobre los eventos del ciclo de vida y es compatible con diferentes marcos y tecnologías.
Ventajas:
Contras:
Qiankun es una poderosa biblioteca de orquestación desarrollada por el equipo de Ant Financial (Alibaba). Utiliza un enfoque HTML parcial para la composición. En el lado de la aplicación de micro-frontend, produce un fragmento HTML simple con todos los puntos de entrada para cargar.
Después de consumir este archivo HTML, el contenedor hace toda la orquestación y monta la aplicación. En esta configuración, HTML parcial juega el papel de un archivo de manifiesto del que hablé en el capítulo anterior.
Ventajas:
Contras:
La federación de módulos , una función proporcionada por Webpack, ha ganado una gran atención y entusiasmo en la comunidad de desarrollo web. Esta tecnología permite a los desarrolladores compartir código entre múltiples aplicaciones en tiempo de ejecución, lo que la convierte en una opción atractiva para crear micro-frontends.
Con su perfecta integración con Webpack y la flexibilidad del tiempo de ejecución, Module Federation se ha convertido en una opción popular para administrar y orquestar micro-frontends.
Ventajas:
Contras:
En esta primera parte de la serie "Viaje de migración de micro-frontend", hemos discutido la motivación detrás de la migración de un monolito web a una arquitectura distribuida y los pasos iniciales tomados para vender la idea al liderazgo.
Exploramos la importancia de un documento de visión técnica que mostrara un análisis de rendimiento detallado y describiera las diferentes fases de la migración.
Luego profundizamos en las consideraciones de diseño para micro-frontends, discutiendo tres enfoques: composición del lado del servidor, composición del lado del borde y composición del lado del cliente.
Cada enfoque tiene sus pros y sus contras, y la elección depende de varios factores, como la sincronización del estado global, la experiencia del cliente, la complejidad de la infraestructura y el almacenamiento en caché.
Además, exploramos bibliotecas de orquestación populares, como single-spa, qiankun y Module Federation, destacando sus características, beneficios y desafíos potenciales.
¡Únase a mí en las próximas partes de la serie a medida que continuamos nuestro viaje de migración de micro-frontend, descubriendo información más interesante y valiosa en el camino!
Publicado originalmente en https://thesametech.com el 18 de abril de 2023.
¡También puedes seguirme en Twitter y conectarte en LinkedIn para recibir notificaciones sobre nuevas publicaciones!