Microfrontends y Módulos Federados

Publicado por Adrián Peña Castro el

FrontMicrofrotendModulos FederadosShellWebpack 5Módulo remoto

Microfrontend, como extensión del término microservicio al mundo front, es un concepto arquitectónico que está despertando mucho interés en los últimos tiempos. Al igual que su hermano de backend, el microservicio, este tipo de arquitectura no es la gallina de los huevos de oro y debe ser entendido y aplicado en su justa medida.

En este artículo explicaremos en qué consisten los microfrontends, que ventajas e inconvenientes presentan y veremos uno de los mecanismos más recientes de generación de microfrontends denominado Módulos Federados y en qué se diferencian de la opción más utilizada hasta ahora, los microfrotends basados en web componentes.

¿Qué es un microfrontend?

La idea que subyace detrás de los microfrontends es muy simple y consiste en descomponer un sistema grande en sistemas más pequeños y sencillos que tengan una funcionalidad concreta y limitada a un ámbito de negocio y que tengan sentido como elementos separados. Estos sistemas más pequeños se pueden desarrollar y desplegar de forma independiente.

Aunque el término Micro Frontend es moderno (apareció por primera vez a finales de 2016 en ThoughtWorks Technology Radar), el concepto no es nuevo ni mucho menos. Su origen directo se encuentra en ideas aparecidas a partir del año 2010, como los sistemas autocontenidos o la descomposición vertical de sistemas.
Viajando un poco más al pasado y haciendo un esfuerzo de imaginación, incluso podíamos ver ya ciertas características de los microfrontends (de una forma bastante arcaica) en los antiguos paneles de control formados a base de frames en los que se incrustaban determinadas páginas con orígenes en diferentes aplicaciones web.

Web con frames, el tatarabuelo de los microfrontends http://www.maths.surrey.ac.uk/explore/nigelspages/frame2.htm

¿Por qué usar microfrontends?

Imaginad que queremos desarrollar una aplicación de una tienda electrónica con sus diferentes secciones: catálogo de productos, carrito de la compra, listado de pedidos, etc.

¿Por qué ibamos a querer dividir el proyecto en diferentes "mini aplicaciones" en lugar de realizar una sola aplicación monolítica como estamos acostumbrados?

Nuestro amigo el monolito ha estado con nosotros desde el inicio de los tiempos.

La clave de los microfrontends reside en la frase clásica "divide y vencerás", la cual aplicamos aquí tanto a nivel de software como a nivel de organización del equipo.

La aplicación de la tienda representada como un monolito.

A nivel de software, descomponiendo la aplicación en otras más pequeñas y centradas en un subdominio del negocio concreto podemos centrarnos de forma específica en el desarrollo de cada una de ellas y abstraernos del resto. Podríamos desarrollar el catálogo de productos sin preocuparnos del carrito o del listado de pedidos.

División de la tienda electrónica en microfrontends.

A nivel de organización del equipo, con este enfoque podemos dividir el equipo en diferentes grupos de desarrollo y especializarlos en un ámbito concreto (equipo de productos, equipo de pedidos) de forma que cada grupo sea responsable del desarrollo de cada uno de los subdominios. Conseguimos así equipos mejor dimensionados (dependiendo de la complejidad de cada microfrontend el equipo estará compuesto por más o menos personas), escalables, desacoplados y más autónomos.

Podemos asignar equipos de diferentes tamaños en función de la complejidad del microfrontend.

No es oro todo lo que reluce

Como es de suponer, nada es gratis en esta vida, y las ventajas de los microfrontends anteriormente expuestas tienen su contrapartida en una serie de retos y problemas que surgen cuando estamos trabajando con este tipo de arquitecturas y que podemos resumirlos en los siguientes puntos:

Composición de la Interfaz de Usuario

Si tengo una aplicación formada por la unión de varias aplicaciones. ¿Cómo se realiza esta unión? ¿Cómo hacer que la interfaz y la transición entre los diferentes microfrontends sea suave? ¿Se parecerá mi aplicación a un frankenstein?

Consistencia de la Interfaz de Usuario

La interfaz de usuario debe ser uniforme y consistente en toda la aplicación. No pueden existir diferentes estilos dependiendo de la sección de la aplicación a la que el usuario acceda.

Dependencias compartidas y bundle size

Si mi aplicación tiene varios microfrontends y cada uno de ellos está programado en Angular, al acceder a cada microfront ¿el navegador tendrá que descargar e interpretar los ficheros JS de Angular varias veces? ¿Mi aplicación pesará más por tener varias veces la misma librería?

Conflictos de versiones

Si dos microfrontends utilizan diferentes versiones de una misma librería ¿qué problemas pueden surgir?

Módulos Federados

Los módulos federados son uno de los mecanismos existentes para la construcción de microfrontends. Este mecanismo hace uso de las nuevas características que proporciona webpack 5 y que permiten a una aplicación Javascript cargar dinámicamente código desde otra aplicación con distinto origen, compartiendo dependencias en el proceso.

Para entender bien los módulos federados y cómo funcionan, vamos a explicar de forma breve algunos de los conceptos que utiliza:

Shell: Podríamos traducirlo como la "carcasa" de la aplicación. Es nuestra aplicación base que puede contener cierta funcionalidad desarrollada en su propio código y que hará uso de diferentes microfrontends para completar todas las funcionalidades del sistema global.

Módulo federado o remoto: No es más que un microfrontend, una parte de la aplicación encargada de realizar cierta funcionalidad y que se compila y despliega por separado para poder ser reutilizada por diferentes aplicaciones.

Tienda electrónica con módulos federados. En rojo la shell y en verde un microfrontend con el catálogo de productos

Reutilización del microfrontend con el catálogo de productos en dos aplicaciones.

Configuración

Para poder comunicar nuestra Shell con los módulos federados necesitamos realizar ciertos cambios en la configuración de webpack (webpack.config):

En primer lugar, cada módulo federado debe exponer qué elementos van a ser compartidos y asignarles un alias que lo diferencie de otros módulos federados. Por ejemplo, si estamos hablando de Angular, podríamos exponer un módulo al completo con todos los componentes, servicios y directivas. Para ello utilizamos la etiqueta "exposes".

Del mismo modo, la Shell necesita conocer qué módulos remotos debe utilizar y en dónde se encuentran localizados. Para ello tenemos dos opciones:

  • Carga de módulos remotos estáticos: En este caso, la configuración del módulo en el webpack.config de la aplicación Shell es estática y debe indicarse en tiempo de compilación. Utilizando la etiqueta "remotes" le indicamos a la shell en qué URL está cada uno de los módulos federados que debe cargar. Cada módulo tendrá un alias que lo identifique y una URL en la cuál se encuentra expuesto.

Ejemplo de configuración estática de módulos federados en Angular utilizando el plugin module-federation de Angular-architects.

  • Carga de módulos remotos dinámicos: En este caso, la configuración no es estática y no es necesario indicarla en el webpack.config en tiempo de compilación. Podemos cargar un módulo remoto en cualquier lugar del código de la shell, pudiendo indicar en tiempo de ejecución la URL en la que se encuentra expuesto el módulo federado.

Ejemplo de configuración dinámica de módulos federados en Angular utilizando el plugin module-federation de Angular-architects.

Una característica muy interesante de los módulos federados es la capacidad de compartir librerías. Mediante una etiqueta "shared" podemos configurar en los ficheros webpack.config una serie de librerías que serán compartidas por la shell y todos los módulos federados de forma que no necesitaremos descargar ni interpretar su código cada vez que accedamos a un módulo. Podemos indicar también la versión compartida o un rango de versiones si queremos permitir cierta flexibilidad.

Una vez configurados los ficheros webpack.config de la shell y de los módulos federados, no existen diferencias apenas entre un módulo local y uno remoto y pueden utilizarse de forma análoga. Para un desarrollador, un módulo remoto no sería más que otro módulo de la aplicación al que accederemos a través de una ruta concreta.

Ventajas e inconvenientes de los Módulos Federados

Con los Módulos federados y la configuración mediante el uso de las nuevas características de webpack 5 conseguimos facilitar el desarrollo de los microfrontends y resolvemos algunos de los retos que presentaban los microfrontends:

  • Composición de la Interfaz de Usuario: Gracias a ser tratados como módulos locales, para el usuario final, la transición entre una sección cargada de forma local de la web y una sección cargada de forma remota no implica ningún cambio apreciable. Para el desarrollador, no hay diferencias entre un módulo local y uno remoto.
  • Consistencia de la Interfaz de Usuario: Este problema no se soluciona con los módulos federados. Depende de que se defina una guía de estilos global entre los diferentes equipos de trabajo o que se definan mecanismos para permitir la modificación de los estilos en los componentes.
  • Dependencias compartidas y bundle size: Al permitirse la compartición de librerías entre módulos remotos, el bundle no tiene duplicados y pesa menos. Además, los microfrontends no tienen que cargar las librerías ya cargadas por la shell (por ejemplo @angular/core). El principal problema en este aspecto es el uso de diferentes microfrontends desarrollados en distintos frameworks (angular, react, vue) ya que prácticamente no compartirían librerías y no tendríamos ninguna ventaja en este aspecto.
  • Conflictos de versiones: La configuración de webpack 5 nos proporciona una serie de herramientas para reducir el impacto de los conflictos de versiones entre librerías, por ejemplo, indicando un rango de versiones admitidas. La mejor opción para evitar el conflicto de versiones es utilizar un monorepositorio para el desarrollo de las aplicaciones como de los diferentes microfrontends.

Diferencias con los microfrontends por Web Components

El uso de Web Components ha sido hasta ahora la alternativa más seria para el desarrollo de microfrontends. Esta técnica se basa en el uso de tecnologías estándar (custom elements, shadow dom, etc.) para construir componentes que puedan ser reutilizados en diferentes aplicaciones. La aparición de los módulos federados no deja obsoleta esta forma de construir microfrontends ya que tienen diferentes características que podemos resumir de la siguiente manera:

Web Components

  • Aíslan del framework utilizado para su desarrollo y evitan problemas de versionado.
  • Cada uno tiene que cargar sus propias librerías, incluso las duplicadas.

Módulos federados

  • Comparten librerías entre ellos
  • Pueden aparecer problemas de versionado y no ofrecen ninguna ventaja con módulos desarrollados en diferentes frameworks.

Dependiendo de las características del sistema que vamos a desarrollar utilizaremos una de las dos técnicas o incluso es posible una combinación de ambas aplicando módulos federados entre microfrontends de un mismo framework y exponiéndolos en forma de web components para su uso con otros frameworks, pero esto lo veremos en detalle en futuros artículos.

Conclusiones

Los microfrontends son la aplicación al front del clásico concepto arquitectónico que consiste en la división de aplicaciones grandes en otras más pequeñas y manejables. Los módulos federados son un mecanismo para la construcción de este tipo de aplicaciones, si bien no son una solución a aplicar de forma indiscriminada para cualquier tipo de arquitectura ya que tienen una serie de inconvenientes que es necesario conocer.

Bibliografía y referencias

https://commons.wikimedia.org/wiki/File:2007-Grandson-Menhir.jpg
https://webpack.js.org/plugins/module-federation-plugin/
https://webpack.js.org/concepts/module-federation/
https://micro-frontends.org/

¿Te ha gustado este post? , ¡síguenos en  Twitter para no perderte todos los demás que vayamos incorporando!

Autor

Adrián Peña Castro

Arquitecto Angular CE Front en knowmad mood. +10 años trabajando con diferentes tecnologías, en especial Java y Javascript. Apasionado de las metodologías de desarrollo.