Video Summary and Transcription
Esta charla discute la transición de un monolito PHP a una configuración de micro-frontends federados en Personio. Implementaron la orquestación y la federación utilizando Next.js como host y enrutador de módulos. El uso de módulos federados y la biblioteca de integración permitió un solo tiempo de ejecución mientras se construye y se despliega de forma independiente. La charla también destaca la importancia de los adoptantes tempranos y los desafíos de construir un sistema de código abierto interno.
1. Introducción a los Micro-Frontends
Hablemos de micro-frontends, del tipo federado. La arquitectura frontend de Personio ha pasado por tres momentos diferentes: monolito PHP, micro-frontends dependiendo del monolito y configuración de micro-frontend federado. El cambio fue necesario porque el monolito se convirtió en una bestia mítica, y la empresa creció más rápido que sus conceptos arquitectónicos. Así, Personia cambió a micro-frontends, con aplicaciones separadas en repositorios separados, activos almacenados en AWS S3, y una aplicación React independiente renderizada en los navegadores de los usuarios.
Hola, amigos, hablemos de micro-frontends, del tipo federado. Ya me presentaron, pero, ya saben, mi nombre es Daniel. He estado trabajando en cosas de frontend durante unos 10 años y actualmente trabajo como ingeniero líder en Personio. Puedes encontrarme allí en caso de que lo que diga sea interesante. Y estoy aquí hoy para contarles una pequeña historia. Es una historia sobre cambio, es una historia sobre evolución, pero es principalmente sobre cómo estamos ejecutando más de 60 micro-frontends propiedad de docenas de equipos y manteniendo nuestra cordura mientras lo hacemos, la mayoría de las veces.
Entonces, sí. La historia comienza, por supuesto, con cambio y lo que está cambiando en este caso es la frontend arquitectura de Personio, que en sus ocho años de existencia ha pasado por tres momentos diferentes. Entonces, el primero fue el monolito PHP, cosas muy simples, el monolito recibía solicitudes, manejaba solicitudes, entregaba cosas al cliente. Luego, el trabajo de Personio de micro-frontends, todavía muy dependiente del monolito para datos y como vehículo de renderización, y finalmente, lo que llamamos configuración de micro-frontend federado que es el punto principal de la charla de hoy. No te preocupes por el tamaño de los gráficos, los veremos más grandes más tarde. Y comencemos primero con, bueno, antes de eso, cuando hablamos de cambio, encuentro que lo más importante que decir sobre el cambio es por qué se necesitaba el cambio, ¿verdad? Porque eso también muchas veces informa por qué terminamos donde terminamos. Así que comienza con el primer momento, cómo Personia llegó a existir y por qué tuvimos que alejarnos de él. Como dije, la mayoría de la gente llamaría a esto legado. Yo lo llamo vintage, porque se aprecia con el tiempo, ya sabes, es una cosa que hace dinero. No me gusta la palabra legado, está muy cargada. Pero es una aplicación monolítica PHP Laravel, hace absolutamente todo, y las personas que construyeron Personia comenzaron el proyecto, se hizo popular, siguieron añadiendo características encima de él, y seguimos añadiendo características encima de él. Y ya sabes, miras atrás un par de años después, y tu proyecto, que comenzó bastante bien, de repente parece esto. Es una bestia mítica, muy poderosa, pero también muy inestable. Y eso es lo que le pasó a Personia, ya sabes, la empresa creció más rápido de lo que sus conceptos arquitectónicos podían. En el front-end específicamente, se veía así. Teníamos jQuery coexistiendo con Laravel y React, y desplegar cualquier cosa tomaba una hora y media o dos horas, si tenías suerte, así que algo tenía que cambiar.
Así que cambió a través de la distribución. Ahora, si estabas alrededor en la escena del front-end en 2019, la palabra de moda más ocupada era micro-front-ends. Eso es lo que hizo Personia. Construyeron micro-front-ends, y nuestro sabor de micro-front-ends parecía algo así. Teníamos aplicaciones separadas en repositorios separados bajo un solo framework que era React. En el momento de la construcción, estas aplicaciones enviarían activos a almacenamiento de archivos en un bucket de AWS S3, y también sincronizarían su última construcción con un servicio interno llamado Servicio de Artefactos. Esta cosa mantenía un mapa de aplicación a activos, algo así. Luego, cuando el monolito recibía una solicitud, preguntaba al Servicio de Artefactos, oye, qué activos debería renderizar aquí, los pasaba al cliente, luego esos serían descargados, JavaScript haría su cosa, y una aplicación React independiente sería renderizada y montada en los navegadores de los usuarios.
2. Orquestación y Federación
Así, pasamos de un monolito a microfrontends separados, lo que inicialmente resolvió algunos problemas pero creó ineficiencias. Para abordar esto, introdujimos la orquestación, que implicaba renderizar a través de algo diferente al monolito. Implementamos la federación, donde los módulos son expuestos y consumidos por un controlador central en tiempo de ejecución, permitiendo lanzamientos de módulos separados. El orquestador de frontend sirve como un controlador ligero y actúa como un enrutador para mapear URLs a módulos.
Entonces, para darles una idea visual de cómo se veía esto, este es el tablero de Persona, y pasamos de esto, el monolito haciendo absolutamente todo, a algo como esto, donde teníamos dos aplicaciones separadas, dos microfrontends separados, eran independientes, no compartían nada. Y esto fue realmente bueno. Resolvimos parte de los problemas, que era que la gente no podía trabajar de forma independiente, teníamos un lío, todo mezclado, y el despliegue era doloroso. Pero también no era tan genial, ¿sabes? Compartir cosas como el estado, las dependencias comunes, todo era muy difícil, requería mucho de coordinación, y después de un tiempo decidimos que realmente no valía la pena el esfuerzo, para compartir estas cosas, así que cada aplicación tenía todo en ella, y era muy ineficiente. Además, estábamos depreciando el monolito, por lo que el vehículo de renderización iba a desaparecer, que es probablemente la razón principal por la que tuvimos que construir algo diferente, ¿verdad?
Ese es el tercer momento, al que llamo orquestación. Y este tercer momento tenía dos objetivos. Uno de ellos era renderizar a través de algo diferente al monolito, porque recuerda que estaba desapareciendo, y el otro era mantener las buenas partes mientras mejorábamos las limitaciones, por lo que las buenas partes incluían la independencia del equipo, y cómo podían construir y lanzar por separado. Las limitaciones eran lo que mencioné antes, era muy ineficiente, difícil de compartir cosas, y así sucesivamente. Y se veía así. Esta es una versión muy poco detallada de ello, entraremos en detalle en un segundo. Pero tenemos un NX monorepo, y luego tenemos nuestros microfrontends siendo expuestos como federados modules, consumidos por una aplicación que llamamos el frontend orquestador, y esa aplicación renderiza cosas y las envía al cliente.
Hablemos del primer aspecto de esto, que es la federación. En términos políticos, esto se trata de provincias, ya sabes, la mayoría son parcialmente independientes con un gobierno central. En nuestro mundo, en JavaScript, es muy similar. Tienes cosas parcialmente autónomas o parcialmente independientes que pueden ser consumidas por un controlador central. Así que tenemos dos aspectos principales, ¿verdad? Tenemos los modules, que son expuestos por un sistema, cualquier sistema, y cualquier cosa puede ser un módulo. Y estos son consumidos por un host. Y también los modules pueden ser hosts ellos mismos. Ahora, si miras esto, podrías preguntarte, bueno, ¿qué lo hace diferente de una instalación regular de NPM? Ya sabes, también consumo modules cuando importo un módulo de NPM, y es una cosa muy pequeña, pero también es muy grande. Lo que es que el consumo de los modules ocurre en tiempo de ejecución. Así que el host no necesita saber qué es el módulo cuando se está construyendo, sólo necesita saber dónde vive. Y luego lo buscará y lo consumirá en tiempo de ejecución. Y esto nos permite hacer algo que es muy poderoso, que es separar los lanzamientos de módulos de un lanzamiento o una reconstrucción del host principal. Cuando estamos hablando de micro frontends y queremos mantener la independencia, bueno, esto es una necesidad.
Bueno, eso es muy divertido. Ya sabes, tienes hosts, tienes modules. Los modules pueden ser hosts, pero todavía necesitas algo central para consumirlos, por lo que necesitamos un controlador central pero ligero. La palabra ligero tiene un poco de acento en ella porque, bueno, realmente queremos que el frontend orquestador, que es como llamamos a nuestro controlador central, sea realmente tonto. Ya sabes, queríamos que hiciera dos cosas. Una de esas dos cosas es que necesita ser un enrutador para poder mapear URLs a modules.
3. Host y Router de Módulos Federados
Usamos Next.js como host y router de módulos federados, pero nuestra configuración no depende de ninguna característica específica de Next.js. Para lograr esto, creamos estándares a través de Monorepo y NX Monorepo, generando una carpeta de frontend para la lógica de negocio y una biblioteca de integración. Esta biblioteca genera automáticamente un componente que puede ser consumido por cualquier microfrontend en el Monorepo o el orquestador de frontend como un módulo federado.
Y la otra es que necesita poder consumir módulos federados, por lo que necesita ser un host. ¿De acuerdo? Básicamente, estas dos cosas. Es un host y router de módulos federados. Y usamos Next.js para eso. Y la razón por la que Next es tan pequeño y está en una esquina, no es que Next no sea genial. Next es genial y nos encanta. Pero es porque nuestra configuración no depende de ninguna característica específica de Next, ¿verdad? Cualquier marco de trabajo o sistema de construcción interno que pueda consumir módulos federados y actuar como un router habría funcionado de la misma manera.
Entonces, tenemos módulos federados. Tenemos la cosa que los va a consumir. Pero recuerda, también teníamos microfrontends existentes que ahora necesitan convertirse en módulos federados, necesitan ser expuestos para que la nueva cosa pueda consumirlos, buscarlos, renderizarlos, hacer todas las cosas buenas que queremos hacer con ellos. Y la forma que encontramos para lograr esto es a través de la creación de estándares, a través de cierta estandarización. Y esto lo hacemos a través de Monorepo, y de hecho, NX Monorepo. Tal vez hayas visto su stand afuera. Son bastante geniales. Lo recomiendo.
Y todo se trata de generar código. Ahora, cada vez que se crea un nuevo microfrontend o cuando se está migrando un microfrontend existente, generamos estas dos cosas. Una carpeta de frontend. Muy aburrido, es solo donde vive toda la lógica de negocio del frontend. No nos importa eso, no hoy. Y una biblioteca de integración. Y aquí es donde ocurren las partes divertidas. Porque esto genera automáticamente un componente que puede ser consumido por cualquier otro microfrontend en el Monorepo o por el orquestador de frontend, ya sabes, el host principal, como un módulo federado. Aquí es donde todo sucede. Y es bastante simple. Se ve así. Tienes algunas propiedades para que el módulo federado sepa dónde viven sus módulos expuestos remotos. Luego exponemos el componente memwise que, ya sabes, este componente de módulo federado que ves ahí, eso es algo interno que construimos y no puedo mostrarte exactamente cómo es, pero podemos hablar de lo que hace más tarde. Es un poco demasiado detalle para los 20 minutos que tengo. Pero ya sabes, ven a buscarme si estás interesado en lo que hace.
4. Biblioteca de Integración y Ejecución Única
Pero en resumen, sabe dónde buscar el módulo federado y cómo renderizarlo. Nx es genial porque hacer generadores es muy fácil, y adaptarlos también es muy fácil. Nos ha ahorrado un montón de trabajo con lo simple que hace la generación de código. Los comandos Nx affected permiten a las personas construir dentro de un monorepo con más de 60 aplicaciones y aún así solo ejecutar un pipeline para sus cambios. NX Effective nos da independencia co-localizada, el beneficio de estar en el mismo código base pero aún independiente. El uso de módulos federados y todas las herramientas dentro del monorepo nos permite tener una única ejecución, aunque estemos construyendo y desplegando de forma independiente. Nos permite compartir estado y código sin problemas con otros microfrontends. Gracias a los módulos federados y el pegamento que tenemos, podemos cargar cosas solo una vez. Ahora, nuestro punto de entrada es mucho más simple, con todo lo demás movido al componente de la aplicación del orquestador.
Pero en resumen, sabe dónde buscar el módulo federado y cómo renderizarlo. Y entonces, sabes, Nx es genial porque hacer generadores es muy fácil, y adaptarlos también es muy fácil. Y nos ha ahorrado un montón de trabajo con lo simple que hace la generación de code. Pero también porque recuerda, queríamos mantener la independencia de los equipos, los comandos Nx affected son increíbles para nuestro caso.
Es lo que permite a las personas construir dentro de un monorepo con más de 60 aplicaciones y aún así solo ejecutar un pipeline para sus cambios. Entonces es algo así, sabes, con una configuración donde tienes una biblioteca A que es consumida por la aplicación A y C, pero no por la aplicación B, los cambios realizados en la biblioteca A resultarán en un pipeline solo para la aplicación A y C. Así que solo la aplicación A y C ejecutarán sus pruebas, serán reconstruidas y serán desplegadas de nuevo. Así que viva por NX Effective. También hay algunos trucos de pipeline para hacer estas cosas dinámicas, pero eso está fuera del alcance.
Entonces, sabes, NX Effective nos da lo que llamo independencia co-localizada, te da el beneficio de estar en el mismo código base, como en el mismo repositorio, pero aún independiente de que cada aplicación es su propia cosa y trabaja a su propio ritmo y es propiedad de su propio equipo. Genial, así que juntemos estas tres piezas y veamos el gráfico inicial en un poco más de detalle. Tenemos el NX monorepo, ¿verdad?, esta cosa tiene bibliotecas compartidas, tiene tooling, mucho tooling, y tiene el pegamento de integración que conecta los Microfrontends con el orquestador. Luego tenemos las aplicaciones frontend en sí, que a su vez tienen su lógica de negocio frontend y exponen una biblioteca de integración, que luego es consumida por el orquestador frontend como un módulo federado y renderizada al cliente, ¿verdad? Diseño muy simple, vamos a verlo. Es muy, no tiene muchas piezas, ¿verdad? Pero como con la mayoría de las cosas simples, el diablo realmente está en los detalles.
¿Recuerdas la biblioteca de integración? Parece pequeña, pero el uso de módulos federados y todas las herramientas que tenemos dentro del monorepo para hacer que este módulo federado se integre sin problemas con otros microfrontends o con el orquestador frontend nos permite tener una única ejecución, aunque estemos construyendo y desplegando de forma independiente. Y una única ejecución, especialmente cuando vienes de no tener una única ejecución como nosotros, sabes, cada aplicación tiene su propia ejecución, es un buen momento. Es genial. Te permite hacer dos cosas muy importantes. Una única instancia de proveedores que luego compartirán estado y compartirán, bueno, lo que sea que pongas en el proveedor, realmente, con otros microfrontends, y te permite compartir code de manera muy fluida, tanto para bibliotecas internas como para dependencias comunes, ¿verdad? Gracias a los módulos Ferrited y todo el pegamento que tenemos, podemos cargar cosas solo una vez. Entonces, para darte un ejemplo muy crudo, todos nuestros componentes del sistema de design, aunque eran reutilizados por la mayoría de los microfrontends, antes se cargaban cada vez que un microfrontend estaba en la pantalla, a veces varias veces por página porque todos usan el componente de tipografía. Ahora eso se carga una sola vez, cada vez que se carga una página y luego se comparte a través de la federación de módulos con cualquier otro microfrontend que lo requiera.
Así es como se veía un punto de entrada. Ves todas estas cosas que parecen de relleno, todos estos proveedores, proveedores de clientes de consulta proveedores de sentry, todas estas cosas globales. Incluso falta en la imagen mucho de la configuración como la configuración de nuestra biblioteca de internationalization configuración de alguna cosa de solicitud que tenemos internamente. Ahora se ve así. Expones tu aplicación, tu punto de entrada, y eso es todo, porque todo lo demás se trasladó al componente de la aplicación del orquestador, recuerda que usamos Next. Esto se comparte en todas las páginas dentro de la aplicación Next. Esa es la belleza de tener una única ejecución, te permite hacer cosas como esta. Teníamos dos objetivos, inicialmente, ¿cómo nos fue con esta cosa que se nos ocurrió? Comparemos. Retrocedí.
5. Lecciones No Técnicas y Caso de Uso
No, no lo hice. Esto fue solo para recordar los objetivos. Renderizar a algo diferente al monolito, y mejorar las limitaciones mientras se mantienen los buenos bits. Los equipos aún construyen y despliegan de forma independiente uno del otro muchas veces al día, y sin conflictos. El nuevo orquestador de frontend es un enrutador y host de módulos ligero. Ahora podemos compartir dependencias y código común fácilmente en una única ejecución. No fue un objetivo inicial, pero las páginas servidas a través del orquestador de frontend han visto una mejora del 30% en las métricas web. Al diseñar y construir un proyecto como este, tenga en cuenta un caso de uso real de inmediato para evitar posibles problemas.
No, no lo hice. Esto fue solo para recordar los objetivos. Renderizar a algo diferente al monolito, y mejorar las limitaciones mientras se mantienen los buenos bits.
Teníamos monolito y micro front-ends a la izquierda, y a la derecha. El primero es la independencia del equipo. ¿Los equipos siguen siendo tan independientes como cuando las aplicaciones vivían en repositorios separados? La respuesta es sí. Gracias a Nx y a algunas de las cosas que hicimos con nuestros pipelines para hacerlos dinámicos, los equipos siguen construyendo y desplegando de forma independiente uno del otro muchas veces al día, y sin conflictos.
¿Tenemos un controlador central? Sí, lo tenemos. En ambos casos, no hay diferencia. Pero ¿es ligero? ¿Es rápido? ¿No hace muchas cosas? En el caso del monolito, lo hacía absolutamente todo. Contenía los data, renderizaba, obtenía cosas. Lo hacía todo. En el nuevo orquestador de frontend, no hace nada. Es un enrutador que también es un host de módulos y eso es todo.
¿Podemos compartir dependencias y código común code fácilmente? Ahora podemos. Porque estamos en una única ejecución. Este, realmente no nos propusimos mejorar esto, pero hemos notado que las páginas que ahora se sirven a través del orquestador de frontend han visto una mejora del 30% en sus métricas web. Lo cual, cuando lo piensas, ya que no tienen que volver a montar todo, tiene sentido porque también estamos compartiendo dependencias. Como dije, no era un objetivo inicial, pero nos encanta verlo.
Ahora, para algunas lecciones no técnicas aprendidas de estar en el equipo que diseñó y construyó este proyecto. Realmente deberías tener un caso de uso real. Si estás haciendo algo así, ten en mente un caso de uso real de inmediato. Quiero decir, teníamos un caso de uso real, pero construido con la idea de que estarás empujando algo a producción lo más rápido posible. Como, elige una página que no sea muy visitada y simplemente ponla ahí. Puede que no funcione bien, no importa. Ponla ahí. No teníamos eso. Terminamos probándolo por primera vez en producción con el tablero de control, la página más visitada. Y Personium, algunos dirían que fue valiente, pero también fue imprudente, y también nos costó muchos dolores de cabeza. Así que, ya sabes, no lo hagas.
6. Desafíos con el Sistema de Código Abierto Interno
La parte más difícil de construir nuevos sistemas de software son las personas, y no estoy hablando de individuos, ¿verdad? Estoy hablando de organizaciones. Queríamos que este nuevo sistema funcionara como un sistema de código abierto interno, pero no funcionó. No teníamos un sistema de infraestructura crítica que respaldara este enfoque. Así que ahora tenemos un equipo que posee el sistema, y funciona mejor.
Lanzar a producción lo más rápido posible en un lugar pequeño. La parte más difícil de construir nuevos sistemas de software son las personas, y no estoy hablando de individuos, ¿verdad? Estoy hablando de organizaciones, así que algo que no mencioné antes es que queríamos que estas dos nuevas piezas funcionaran como un sistema de código abierto interno, ¿sabes? Como, seríamos el grupo de mantenedores. Las personas colaborarían. Nosotros, ya sabes, contribuiríamos, colaboraríamos con ellos. Sería genial, ¿sabes? Sería glorioso. Eso no funcionó. No teníamos ningún sistema de infraestructura crítica que funcionara de esta manera, y resulta que el camino inverso donde primero construyes un sistema y luego esperas que las estructuras organizativas de tu empresa se adapten al sistema existente, no funciona. Así que, ya sabes, esto podría sonar genial, pero ahora tenemos un equipo que posee las cosas, y hay ideas muy claras de a quién necesitas contactar si algo se rompe o quién está a cargo de desarrollarlo, y funciona mejor, ¿sabes? La organización Personia no estaba lista para una idea como esta, y perdimos mucho tiempo tratando de hacerla funcionar.
7. Importancia de los Adoptantes Tempranos y Conclusión
Los adoptantes tempranos son cruciales para construir algo nuevo. Proporcionan valiosos comentarios e ideas. Si te encuentras en una posición similar, considera el patrón arquitectónico de microfrontends federados. Un agradecimiento al equipo original y gracias por asistir a la masterclass.
Y finalmente, cuando estás construyendo algo nuevo, tus adoptantes tempranos son los mejores adoptantes. Te amarán, te odiarán, pero lo más importante, te harán saber qué funciona y qué definitivamente no funciona, ¿verdad? Así que encuentra adoptantes tempranos y valóralos. Son los mejores.
Ahora, algunos de ustedes podrían estar en posiciones similares, y podrían estar pensando, eh, eso suena interesante, tal vez debería intentarlo. Ya sabes, la respuesta siempre es, es bastante simple, es un tal vez, ya sabes, depende. Nuestra situación era bastante especial. Teníamos varios equipos que necesitaban lanzar a demanda, y necesitaban hacer estos lanzamientos disponibles para los clientes de inmediato. Ya teníamos experiencia con microfrontends, así que sabíamos cómo ejecutar un sistema distribuido de frontend federado, no, no federado. Estábamos depreciando nuestro mecanismo de entrega existente, por lo que nos vimos obligados a construir algo nuevo. Y teníamos algo de experiencia interna construyendo un sistema similar. Creo en lo que construimos, pero si algunas de esas cosas no estuvieran allí, podríamos haberlo arreglado en su lugar, en lugar de construir algo diferente. Si tu posición se parece en algo a la nuestra, no tiene que ser exactamente como la nuestra, pero algo similar a la nuestra, entonces tal vez considerar esta idea, este patrón arquitectónico de microfrontends federados podría valer la pena para ti. Eso es el final de la historia, pero antes de pasar a las preguntas y respuestas, quiero dar un agradecimiento a las caras en esta diapositiva. Ellos fueron el equipo original que trabajó conmigo en esto. Gente muy genial. Sí, solo quería mostrar sus caras. Y gracias por venir. Gracias por escuchar. Gran masterclass. Muchas gracias.
Alternativa a NX y TurboRepo
Podríamos usar una alternativa. Lo que necesitamos de NX es generar código fácilmente y el comando afectado. No he investigado realmente TurboRepo, pero si TurboRepo puede hacer algo así que permita que las aplicaciones de monorepo sigan sintiéndose independientes y trabajen de forma independiente, entonces también funcionaría.
Tenemos muchas preguntas. No podremos responder a todas las preguntas, así que si tienes preguntas específicas que ves en Sli.do, por favor, vótalas y podemos responder a esas primero. Bien. Entonces, primera pregunta. ¿Depende tu configuración de la funcionalidad específica de NX, o podrías usar una alternativa como TurboRepo? Podríamos usar una alternativa. Lo que necesitamos de NX es generar code fácilmente y el comando afectado, ya sabes. No he investigado realmente TurboRepo, pero si TurboRepo puede hacer algo así que permita que las aplicaciones de monorepo sigan sintiéndose independientes y trabajen de forma independiente, entonces también funcionaría. Genial, sí. Tampoco lo he probado, así que es, ya sabes, ve a probarlo.
Versionado y Diversidad Tecnológica
Nuestra estrategia para el versionado de MicroFrontEnds es tener un único paquete raíz JSON, asegurando una única versión de dependencias en todo el monorepo. Tenemos un versionado estricto en nuestros módulos federados para asegurar que todos obtengan la misma versión. Servimos un único archivo de entrada remota sin hashing, pero estamos introduciendo un hash para la versión. Aunque usamos React para la homogeneidad, los equipos pueden tomar decisiones sobre bibliotecas y marcos específicos. Actualmente, no soportamos la renderización del lado del servidor con Módulos Federados, pero puede evolucionar en el futuro.
¿Qué pasa con la versión de tu MicroFrontEnd? ¿Qué pasa si los modules comunes difieren entre esas versiones? ¿Cómo manejarías esto en tu aplicación host final? Correcto. Ahora mismo, nuestra estrategia para resolver eso es no permitirlo. Así que eso es otra cosa que NX hace por ti. Tiene un único paquete raíz JSON. Así que solo tienes una única versión de dependencias en todo el monorepo. Hace que a veces la actualización sea dolorosa, pero resuelve algunos de los problemas en este caso.
Otra cosa que tenemos es que tenemos un versionado estricto en nuestros modules federados, lo que significa que cuando una dependencia llega y se sirve a un MicroFrontEnd como un módulo federado, sabemos que todos obtendrán la misma versión. Para nuestras propias cosas de versionado interno, en este momento, realmente no tenemos eso. Las nuevas versiones son siempre la última versión. Servimos un único archivo de entrada remoto sin hashing, pero estamos introduciendo un hash para la versión. ¿Recuerdas el servicio de artefactos que mencioné? Tenemos una nueva versión de eso, que mantendrá la referencia a cuál es el último archivo de entrada y lo serviremos al orquestador cuando se solicite.
Sí, eso tiene sentido. Voy a destacar una pregunta que se hizo aquí que no estaba en la parte superior, que es, tienes un monorepo, y eso te permite tomar decisiones de un solo punto, como acabas de mencionar, fijando versiones. ¿Pero tienes alguna diversidad tecnológica en la pila? ¿La gente está usando quizás diferentes bibliotecas, frameworks, patrones arquitectónicos patterns, o es algo homogéneo? No del todo homogéneo, pero está cerca. Solo usamos React. Eso ya es una gran ventaja, porque nos permite simplificar las tooling que crean modules autoritativos, solo tuvimos que lidiar con un framework. Y proporcionamos algunas cosas de serie que son lo que esperamos que la gente use, como React Query, por ejemplo. Ese es nuestro mecanismo de gestión de estado del servidor. Pero aún así, los equipos pueden tomar decisiones sobre los detalles de lo que usan. Así que, por ejemplo, si un microfrontend realmente necesita algún state management para él, aparte del estado del servidor, pueden traer Redux o Jotai o lo que quieran. Así que, es homogéneo en las grandes piezas, no tanto en las más pequeñas.
Bien. Así que, aquí hay una pregunta que ha sido votada muchas veces. Intentamos la misma solución, pero nos quedamos atascados en SSR. ¿Cómo están trabajando ustedes con SSR y Módulos Federados? Sí, esa es buena. No lo estamos. No tenemos la necesidad de hacer eso ahora mismo. Y sé que es un punto importante. Los Módulos Federados no están realmente bien configurados aún para la renderización del lado del servidor, o al menos no lo estaban la última vez que lo comprobamos. Las cosas podrían haber evolucionado mientras tanto, y definitivamente evolucionarán eventualmente para soportar eso.
Manejo de Datos en Tiempo Real y Federación de Módulos
Nuestra aplicación depende de los datos de RRHH en tiempo real, por lo que no usamos mucho SSR. Utilizamos una caché compartida para deduplicar solicitudes y mejorar la eficiencia asíncrona. Los cambios disruptivos en los módulos federados se manejan con una herramienta que permite retrocesos fáciles. Implementamos nuestra propia solución de federación de módulos, que es similar a las existentes. Requerimos una cobertura de código del 100% para las bibliotecas compartidas para minimizar los problemas causados por los cambios de un equipo que afectan a otro.
Nuestra aplicación depende mucho de que los data estén actualizados en tiempo real, porque son data de HR. Es muy importante que las cosas estén actualizadas. Por lo tanto, realmente no usamos mucho SSR. Sí. De hecho, noté que estás usando React Query, ¿es correcto? Sí. O algo así. Entonces, probablemente tienes una caché compartida, ¿es así como deduplicas las solicitudes, te aseguras de que cada paquete no haga una obtención de datos innecesaria? Sí, exactamente. Y esa es la capa que nos permite ser más eficientes con nuestras solicitudes asíncronas.
Sí, eso es realmente genial. Entonces, aquí está la pregunta que ya tocamos un poco, pero creo que necesita un poco más de explicación. ¿Cómo manejas la implementación de cambios disruptivos en los módulos federados, que necesitan despliegues independientes? Correcto. Sí. Tenemos, como dije, esta herramienta que estamos implementando ahora, que es la nueva versión de el Servicio de Artefactos, hace que sea muy simple retroceder. Tiene una interfaz que podemos usar para decir, hey, este se rompió, márcalo como inestable y devuelve el último. Entonces, se resuelve con tooling, básicamente.
Bueno, esto nos lleva a nuestra siguiente pregunta. ¿Utilizaste alguna biblioteca existente de federación de módulos o implementaste la tuya propia? Y si hiciste la tuya, ¿qué opinas de algunas de las soluciones listas para usar que hay por ahí? Correcto. Creo que uno de mis compañeros de equipo sería el mejor para responder a esta pregunta. Pero si recuerdo correctamente, y Rob, lo siento si me equivoco, terminamos implementando la nuestra, pero se parece mucho a algo existente. Fue más como que ajustamos pequeñas partes de ella para adaptarla a nuestro caso de uso específico, considerando una bifurcación de lo que había por ahí para el plugin de módulos federados de NextJS, creo. ¿Y qué considero? Quiero decir, todos son geniales. Si puedes usarlos, úsalos. No tiene sentido implementar el tuyo propio para algo que ya ha sido resuelto. Simplemente no funcionó del todo para lo que queríamos.
Genial. ¿Cómo manejas cuando un equipo rompe las cosas de otro equipo a través de una biblioteca compartida? ¿Hay algún tipo de ritual de vergüenza para ponerlos en una esquina, hacer que se pongan un sombrero gracioso, señalarlos? No, pero desearía que lo tuviéramos. No, quiero decir, somos muy estrictos en las bibliotecas mismas. Las bibliotecas que se comparten con diferentes microfrontends, requieren una cobertura de code del 100%. No estoy diciendo que eso lo haga más seguro. Pero generalmente al menos hace que la gente piense más en sus cambios.
Revisión de Código, Seguridad de Tipos y Compartición de Datos
Los equipos revisan el código utilizando un archivo de propietarios de código detallado y requieren la aprobación de todos los equipos consumidores antes de enviar a producción. TypeScript y la biblioteca de integración garantizan la seguridad de tipos y las finalizaciones de código en VS Code. Los contextos comunes entre microfrontends se comparten a través de bibliotecas de datos que utilizan React Query. El monorepo en sí proporciona información sobre los datos disponibles y el acceso a la caché.
Y también deben ser revisados por el equipo que los está utilizando. Porque usamos un archivo de code propietarios muy detallado. Y luego, mientras se construyen las solicitudes de fusión que lo enviarán a producción, necesita requiere la aprobación de cada equipo que lo consume. Así es como nos protegemos de ese escenario. No quiere decir que no suceda, ¿verdad? Pero cuando sucede, también nos lanzamos sobre ello como equipo. Como un grupo de personas de diferentes sitios para resolverlo. Sin avergonzar a nadie.
Sí, eso tiene sentido. De hecho, destacaré otra pregunta de aquí, que no puedo encontrar ahora mismo. Pero era acerca de... Así que supongo que también usas algo de TypeScript para obtener type safety en todos los paquetes Pero, ¿qué pasa con cosas como las code finalizaciones y la función de comando-clic dentro de VS Code, por ejemplo? ¿Funcionan cuando estás federando en tiempo de ejecución?
Sí, lo hacen, porque tenemos este paquete de integración que te mostré, la biblioteca de integración. Eso se consume como cualquier otra importación regular, ¿verdad? Lo que hace en tiempo de ejecución está dentro de él. Cada aplicación, cada microfrontend se desarrolla individualmente. Todo tiene seguridad de tipos. Todo está en TypeScript. Es seguro en cuanto a tipos. Y es consumido por el orquestador de frontend que también es seguro en cuanto a tipos, y el lado asíncrono que podría romperse sucede bajo el capó, y nadie realmente lo toca. Así es como nos protegemos de eso. Genial.
Tenemos tiempo para una pregunta más. Ya hemos tocado un poco esto, pero creo que vale la pena explorarlo un poco más. ¿Cómo compartes contextos comunes entre microfrontends? Así que supongo que esto es contexto en tiempo de ejecución, cosas como data. Mencionaste React Query. Pero, ¿podrías decir unas palabras más sobre cómo se orquesta todo eso? ¿Cómo saben los equipos que están construyendo una funcionalidad particular qué data está disponible? ¿Qué se va a precargar en la caché? ¿Importa, etc., etc.?
Sí, importa, y ese es un punto que aún no hemos resuelto completamente. Tenemos una idea, y ya funciona. Tenemos lo que llamamos bibliotecas de data. Así que los equipos proporcionan bibliotecas de data comunes que utilizan, bajo el capó, utilizan React Query. Exponen hooks para que podamos compartir las mismas claves de consulta, y por lo tanto acceder a la misma caché cuando diferentes equipos la utilizan. Pero como estamos migrando microfrontends existentes que son independientes, aún no están del todo allí. Pero cuando lleguen, no tendremos el problema de saber qué está disponible porque dentro del monorepo en sí, te dirá qué puedes buscar de forma segura accediendo a una caché si existe. Genial, eso es realmente interesante, de hecho. Impresionante.
Una última pregunta para mí. ¿Cuál es tu tipo de letra Serif favorito? Meriwether. Genial. Bueno, muchas gracias, y te dejo ir. Buen trabajo en la charla. Gracias. Aplaudamos una última vez.
Comments