Antecedentes

Cuando empezamos a desarrollar esta nueva aplicación teníamos en mente una estructura de microservicios, separando tanto la UI como el API de los servicios implicados. Creímos que sería más fácil desarrollar aplicaciones en paralelo.

La realidad es que, tras varios servicios desarrollados, el API sí tiene una entidad propia mientras que la UI de éstos acaba siendo bastante simple, con pocas vistas y utilizando, en su mayoría, las mismas librerías y componentes comunes a todos los diferentes servicios.

Además, modificar algo simple, como un detalle en la cabecera, que estuviera en todas estas UI implicaba actualizar la librería de componentes común y volver a desplegar cada una de las aplicaciones. Sin contar con que cada UI tiene un pod de kubernetes independiente, con toda la infraestructura basada en nube que implica. 

Esto supone mucho más gasto, tanto en infraestructura como en tiempo de desarrollo de nuevas funcionalidades.

Soluciones elegidas para el problema

División de la aplicación en módulos

El primer paso ha sido unificar todos los directorios del código fuente en un único directorio llamado app. Dentro de este se ha dividido la aplicación en módulos siguiendo dos criterios:

Una vez separados por módulos, cada uno de ellos tendrá control sobre sus propias llamadas al API (que, aunque separada por microservicios y rutas, está en el mismo dominio), estado interno de sus servicios (Con Vuex), definición de rutas y las vistas que éstas cargarán, etc.

Intentando estandarizar el proyecto, también se ha decidido separar vistas de componentes, tal y como hace la instalación por defecto de Vue con vue-cli y router o Nuxt.

Llamadas a APIs backend

Cada módulo debe tener separadas sus propias llamadas al API. Heredarán todos de una capa sobre axios que enviará los tokens automáticamente, teniendo una única configuración para toda la aplicación. Aún así, si un equipo de desarrollo necesitara hacer llamadas propias o configurar su propia versión de axios podría perfectamente.

La idea es agrupar semánticamente las APIs. Si se tiene más de una dependencia con llamadas de API se pueden crear más de un fichero de llamadas. La solución de consenso en cuanto a nomenclatura ha sido poner a todos los ficheros de api este sufijo para distinguirlos fácilmente.

Componentes

Aquí se añadirán todos aquellos componentes que no se carguen directamente desde una ruta de vue router. Siguiendo las recomendaciones de Vue School para grandes aplicaciones se darán nombres correctos, obviamente, a cada componente pero no se harán subcarpetas dentro de esta carpeta, estando todos los componentes en la raíz.

Los componentes habrán de nombrarse usando únicamente PascalCase para seguir los estándares de uso de la comunidad JavaScript. 

No será obligatoria ninguna metodología de SCSS/CSS para poder aceptar las PR en el repositorio pero sí se comprobará que esté bien realizado, utilizando las variables CSS del proyecto y el uso de reglas válidas que no interfieran con el resto de grupos de desarrollo.

Igualmente, será obligatorio cumplir las reglas de los linter del proyecto, que se comprobarán antes de poder hacer push así como mientras se desarrolla. Se ayudará a los diferentes equipos de trabajo a configurar sus IDE de forma adecuada.

Vistas

Componentes que se cargan desde una ruta. Si está en la definición de las rutas del módulo se añadirá en esta carpeta. Las vistas, al fin y al cabo, siguen siendo componentes de Vue, pero, por legibilidad y estandarización del repositorio tal y como se trabaja en este tipo de proyectos, se dividen en estas dos categorías.

Obviamente, todas las reglas que se aplican a los componentes se aplicarán a las vistas. Al fin y al cabo, en Vue siguen siendo componentes.

Rutas

Todos los módulos definirán sus propias rutas en un fichero que se inyectará como dependencia en las rutas del sistema. La configuración de las rutas del sistema o de otros módulos deberán permanecer inalterables.

Como serán diferentes grupos de trabajo los que estarán envueltos, en caso de colisión de nombres se resolverá por los interesados, siempre pensando en las URL amigables de cara al usuario, no a la gestión interna del repositorio, que aún en 2022 hay que recordárselo a los desarrolladores.

Estado de la aplicación local al módulo

En lugar de almacenar el estado de la aplicación en una única store con todos los métodos, todos los módulos deberán tener sus propios estados locales a través de módulos de Vuex.

Esto añade una leve dificultad al desarrollo, ya que será necesario que se especifique el nombre al tratar tanto con el estado en sí como con mutaciones o acciones pero será mucho más fácil depurar cualquier fallo derivado del estado.

Con Vue 3 tenemos la opción de pasarnos para la gestión del estado la nueva librería Pinia pero, por el momento, necesitamos que pueda mantener más módulos y nos dé más información a la hora de los commits síncronos para depuración, ya que vamos a estar muchos grupos trabajando a la vez.

Actualización de los módulos

La actualización de Vue 2 a Vue 3 ha sido bastante sencilla. Únicamente ha habido que realizar los pasos que en la propia documentación de Vue han añadido para que el cambio sea totalmente retrocompatible. 

Por temas de tiempo de desarrollo, no se va a obligar a todos los equipos a volver a escribir su código en Vue 3 puro, por lo que la retrocompatibilidad era la única opción viable. Por suerte, es inmediato y funciona sin tener que modificar nada. 

Sólo hemos encontrado problemas con el componente que estábamos utilizando de calendario, que se ha sustituido por otro.

Como librería de componentes estamos usando PrimeVue. En esta nos encontramos un detalle a tener en cuenta. y es que al importar componentes que estén hechos de forma nativa en Vue 3, por el modo de retrocompatibilidad hay que especificar explícitamente que se importen como componentes Vue 3. Se hace de esta forma, al importar los componentes:

import Button from 'primevue/button';
import Dialog from 'primevue/dialog';
import Dropdown from 'primevue/dropdown';
import Message from 'primevue/message';
 
const compatMode3 = { MODE: 3 };
Dialog.compatConfig = compatMode3;
Dropdown.compatConfig = compatMode3;
Button.compatConfig = compatMode3;
Message.compatConfig = compatMode3;

Esto habrá que hacerlo para todos los componentes de Primevue, y para los de otras librerías que podamos utilizar que también tenga componentes Vue 3.