Trabajando con Monorepos

Jerome Olvera
Javascript Mérida
Published in
6 min readApr 17, 2020
https://unsplash.com/photos/b3PuuRU8IPc

Una definición rápida que podría dar de la palabra “Monorepo” y básicamente es cuando pones “Multiples proyectos” en un mismo repositorio de código, donde “proyectos” son aplicaciones, servicios, librerías y frameworks.

Los monorepos no son una técnica exclusiva de algún lenguaje o framework y tampoco son nada nuevos.

Esta técnica es conocida tanto en grandes empresas como en pequeños equipos, en JavaScript tenemos opciones para hacerlos las cosas muy fácil como Yarn Workspaces o Lerna.

De grandes empresas se conoce que Facebook, Google, Netflix y Uber usan Monorepos para manejar sus proyectos, con masivas cantidades de código que require de muchas manos para mantener.

Google describe los retos que enfrentaron en su Monorepo actualizando la version de TypeScript
Google describe los retos que enfrentaron en su Monorepo actualizando la version de TypeScript

Propiedades

Algunas propiedades que incentivan el uso de los Monorepos

Thrid-Party dependencies

Probablemente cuando estas desarrollando en una serie de apps tengas alguna dependencia que se comparte entre 2 o mas proyectos, algún validador de strings, hash de password, cliente de peticiones http, etc.

Por la salud de tu proyecto puede ser que estes regularmente verificando como te afectaría que alguna dependencia que tengas incluya en su actualización algún breaking-change o que la misma dependencia quede deprecada. Si algo de lo anterior llega a pasar tendrías que identificar cada lugar donde esta dependencia sea utilizada y remplazar.

Una ventaja que se incluye en los monorepos es mantener una version global de cualquier dependencia y poder darle mantenimiento desde un solo lugar y cuando sea necesario cambiar puedes tener mayor visibilidad en los lugares que se pueden ver afectados por este cambio y en un commit o PR al proyecto solucionar el problema.

También puedes agrupar todas tus dependencias de terceros en una sola dependencia dentro de tu repo y hacer que tus subproyectos la implementen.

In-House dependencies

Una practica muy común en JavaScript que sigo y que es muy popular en algunos proyectos como React, Yarn, Apollo es convertir parte de tu propio código en utilidades o funciones que agrupen un set de herramientas que se puedan volver una dependencia.

Un ejemplo muy común es mover tus shared-components en React a una UI Kit y en lugar de usar tus componentes como…

import { Button } from '../../../../components'

Solo tengas que…

import { Button } from '@mycompany/components'

Así mismo, esta librería de componentes tal vez siga un diseño base (Design System) que tu empresa o que tu proyecto implemente y también mantienen otros desarrollos basados en React, como un Blog en Gatsby, una Landing en Next y una WebApp en React, todos estos proyectos pueden compartir esa misma dependencia y maximizar la reusabilidad de el código creado en el equipo, en lugar de tener una implementación especifica para cada plataforma.

En mi experiencia

Gracias a herramientas como Yarn en Node se puede llevar muy bien el primer punto de las dependencias con versiones fijas, y para el segundo caso me incentiva mas a desarrollar mi código de forma mas limpia con una API mas rica, para que mas personas puedan rehusar algo que ya hice.

En el caso del despliegue continuo, Netlify tiene soporte para monorepos, por lo que puedo desplegar mis sitios estáticos bastante sencillo, aunque para heroku aun tuve que escribir un poco mas de script para desplegar las aplicaciones de servidor.

Un ejemplo rápido de como quedaría la unidad de mis módulos en mi monorepo.

Trade-offs

Cada decisión técnica se debe tomar con responsabilidad y en equipo.

Mantener un solo repositorio con mucho código require esfuerzo adicional tanto para las herramientas de despliegue, control y disciplina del equipo para hacerlo bien.

En el caso de JavaScript vas a terminar con unos node_modules muy grandes, aunque estando en diferentes proyectos también estarán ahi.

En mi caso uno de las cosas que mas se me complicaron fue trabajar con los sistemas de despliegue automático y pipelines, tuve que escribir mas configuración para permitirle a mi repositorio desplegar cada uno de sus proyectos por aparte, que haciendo uno por uno es mas rápido.

Muchos mas YAMLS…

Tanto como Yarn y Lerna me permitieron lograr mi trabajo, Yarn me permitió enlazar proyecto con dependencias in-house privadas, cosa que con Lerna algunas dependencias tendría que estar ya desplegadas en un repositorio public como NPM (en caso de no tener contratado un espacio privado en NPM).

Para el caso de Yarn Workspaces, se sigue una técnica de Hoisting para las dependencias, ayuda mucho para tener menos node_modules repetidos, pero no todos los módulos en NPM son compatibles con el Hoisting, algunas dependencias que me causaron problemas temprano fueron create-react-app y react-native , me apoye de la documentación de Yarn Workspaces para deshabilitar el hoisting solo en esas dos dependencias y poder hacer mi trabajo. Mas tarde se agregaría el soporte a esas dos dependencias y ya no tendría que hacer configuración adicional.

Finalmente no he trabajado un monorepo tan grande pero en mi investigación descubrí que algunos problemas que sufren repos mas masivos van con dependencias externas donde tiene que incluir binarios completos para evitar tener problemas en el ciclo de compilación, lo que lleva a manejar archivos muy grandes en tu repositorio. Para mi esto tal vez se vio reflejado con un tiempo de instalación de los módulos con Yarn muuuy largo.

En Conclusión

Esto comenzó por un proyecto Node que estaba dividido cliente servidor y las personas que íbamos a colaborar inicialmente en ese proyecto éramos 2, ese proyecto estaba un poco antiguo y usaba versiones de Node diferentes lo cual nos complicaba el proceso de Setup, la primera decisión que tomamos fue actualizar las dos versiones de Node a una misma version en LTS y una vez que ese estabilizó el proceso de Setup pudimos unificar muchas cosas en ambos proyectos que se pudieron controlar desde un solo repositorio y ahora cada que sea necesario migrar una version de alguna dependencia de Node o la misma version de Node, nos da mas control ya que lo tenemos todo en un mismo sitio (pero separado lógicamente).

Después de los trade-offs y practica hemos podido mejorar el proceso de Setup, Despliegue, etc, automatizando varias cosas y aun lidiando un poco con le versionado de los módulos, por lo que al final ademas de experiencia hemos podido aprovechar los Wins que esta técnica ofrece.

Como ultima recomendación si estas interesado en experimentar dicha tenía sea ver una oportunidad en proyectos donde se piensa que se comparte código, donde se sienta que se están copiando y pegando cosas en diferentes partes del proyecto o donde se sienta que la aplicación realmente tiene el mismo contexto para permanecer en un mismo lugar. siempre es respetable que si una técnica no te favorece a ti o a tu equipo no tengas que incluirla en tu proyecto.

Links Externos

--

--

Jerome Olvera
Javascript Mérida

Staff Software Engineer en GBM Grupo Bursátil Mexicano