Existen dos estrategias principales para alojar y gestionar el código a través de Git: monorepo vs multi-repo. Ambos enfoques tienen sus pros y sus contras.

Podemos utilizar cualquiera de los dos enfoques para cualquier base de código en cualquier lenguaje. Puedes utilizar cualquiera de estas estrategias para proyectos que contengan desde un puñado de bibliotecas hasta miles de ellas. Incluso si se trata de unos pocos miembros del equipo o cientos, o si quieres alojar código privado o de código abierto, puedes optar por monorepo o multi-repo en función de varios factores.

¿Cuáles son las ventajas e inconvenientes de cada enfoque? ¿Cuándo debemos utilizar uno u otro? Averigüémoslo.

¿Qué son los repositorios?

Un repo (abreviatura de repositorio) es un almacén para todos los cambios y archivos de un proyecto, lo que permite a los desarrolladores «controlar la versión» de los activos del proyecto a lo largo de su etapa de desarrollo.

Normalmente nos referimos a los repositorios Git (como los que proporcionan GitHub, GitLab o Bitbucket), pero el concepto también se aplica a otros sistemas de control de versiones (como Mercurial).

¿Qué es un monorrepo?

El enfoque monorepo utiliza un único repositorio para alojar todo el código de las múltiples bibliotecas o servicios que componen los proyectos de una empresa. En su versión más extrema, todo el código base de una empresa – que abarca varios proyectos y está codificado en diferentes lenguajes – se aloja en un único repositorio.

Los Beneficios de Monorepo

Alojar todo el código base en un único repositorio ofrece las siguientes ventajas.

Reduce las barreras de entrada

Cuando los nuevos miembros del personal empiezan a trabajar en una empresa, necesitan descargar el código e instalar las herramientas necesarias para empezar a trabajar en sus tareas. Supongamos que el proyecto está disperso en muchos repositorios, cada uno con sus instrucciones de instalación y las herramientas necesarias. En ese caso, la configuración inicial será compleja y, en la mayoría de los casos, la documentación no estará completa, lo que obligará a estos nuevos miembros del equipo a pedir ayuda a sus colegas.

Un monorepo simplifica las cosas. Al haber una única ubicación que contiene todo el código y la documentación, se puede agilizar la configuración inicial.

Gestión centralizada del código

Tener un único repositorio da visibilidad de todo el código a todos los desarrolladores. Simplifica la gestión del código, ya que podemos utilizar un único gestor de incidencias para vigilar todas las incidencias a lo largo del ciclo de vida de la aplicación.

Por ejemplo, estas características son valiosas cuando un problema se extiende a dos (o más) bibliotecas hijas con el error existente en la biblioteca dependiente. Con múltiples repositorios, puede ser un reto encontrar el trozo de código donde se produce el problema.

Además, tendríamos que averiguar qué repositorio utilizar para crear la incidencia y, a continuación, invitar y etiquetar a miembros de otros equipos para que ayuden a resolver el problema.

Sin embargo, con un monorrepo, tanto la localización de los problemas del código como la colaboración para solucionarlos son más sencillas.

Refactorizaciones de la aplicación sin complicaciones

Al crear una refactorización del código en toda la aplicación, se verán afectadas múltiples bibliotecas. Si las alojas en varios repositorios, la gestión de todos los pull requests para mantenerlos sincronizados entre sí puede resultar un reto.

Un monorepo facilita la realización de todas las modificaciones de todo el código de todas las bibliotecas y su envío bajo un único pull request.

Más difícil de romper la funcionalidad adyacente

Con el monorepo, podemos configurar todas las pruebas de todas las bibliotecas para que se ejecuten cada vez que se modifique alguna de ellas. Como resultado, la probabilidad de hacer un cambio en algunas bibliotecas ha minimizado los efectos adversos en otras bibliotecas.

Los equipos comparten la cultura del desarrollo

Aunque no es imposible, con un enfoque monorrepo, resulta difícil inspirar subculturas únicas entre los distintos equipos. Dado que compartirán el mismo repositorio, lo más probable es que compartan las mismas metodologías de programación y gestión y que utilicen las mismas herramientas de desarrollo.

Problemas con el enfoque monorrepo

Utilizar un único repositorio para todo nuestro código tiene varios inconvenientes.

Ciclos de desarrollo más lentos

Cuando el código de una biblioteca contiene cambios de ruptura, que hacen que las pruebas de las bibliotecas dependientes fallen, el código también debe ser corregido antes de fusionar los cambios.

Si estas bibliotecas dependen de otros equipos, que están ocupados trabajando en alguna otra tarea y no son capaces (o no están dispuestos) a adaptar su código para evitar los cambios de ruptura y hacer que las pruebas pasen, el desarrollo de la nueva característica puede estancarse.

Es más, es muy posible que el proyecto empiece a avanzar solo a la velocidad del equipo más lento de la empresa. Este resultado podría frustrar a los miembros de los equipos más rápidos, creando las condiciones para que quieran abandonar la empresa.

Además, una biblioteca tendrá que ejecutar las pruebas de todas las demás bibliotecas también. Cuantas más pruebas haya que ejecutar, más tiempo se tarda en hacerlo, lo que ralentiza la rapidez con la que podemos iterar en nuestro código.

Requiere la descarga de todo el código base

Cuando el monorepo contiene todo el código de una empresa, puede ser enorme y contener gigabytes de datos. Para contribuir a cualquier biblioteca alojada en él, cualquiera necesitaría descargar todo el repositorio.

Tratar con una amplia base de código implica un mal uso del espacio en nuestros discos duros e interacciones más lentas con ella. Por ejemplo, acciones cotidianas como ejecutar git status o buscar en la base de código con una regex pueden tardar muchos segundos o incluso minutos más de lo que tardarían con múltiples repos.

Las bibliotecas no modificadas pueden tener una nueva versión

Cuando etiquetamos el monorepo, a todo el código que contiene se le asigna la nueva etiqueta. Si esta acción desencadena una nueva publicación, entonces todas las bibliotecas alojadas en el repositorio serán recién publicadas con el número de versión de la etiqueta, aunque muchas de esas bibliotecas no hayan tenido ningún cambio.

La bifurcación es más difícil

Los proyectos de código abierto deben facilitar al máximo la participación de los colaboradores. Con múltiples repositorios, los colaboradores pueden dirigirse directamente al repositorio específico del proyecto al que quieren contribuir. Sin embargo, con un monorepositorio que aloja varios proyectos, los colaboradores deben navegar primero hacia el proyecto correcto y tendrán que entender cómo su contribución puede afectar a todos los demás proyectos.

¿Qué es el Multi-Repo?

El enfoque multirepo utiliza varios repositorios para alojar las múltiples bibliotecas o servicios de un proyecto desarrollado por una empresa. En su punto más extremo, alojará cada conjunto mínimo de código reutilizable o funcionalidad independiente (como un microservicio) bajo su repositorio.

Ventajas del Multi-Repo

Alojar cada biblioteca de forma independiente de todas las demás proporciona una gran cantidad de ventajas.

Versionado independiente de bibliotecas

Al etiquetar un repositorio, se asigna la etiqueta «nuevo» a todo tu código base. Dado que solo el código de una biblioteca específica está en el repositorio, la biblioteca puede ser etiquetada y versionada independientemente de todas las demás bibliotecas alojadas en otros lugares.

Tener una versión independiente para cada librería ayuda a definir el árbol de dependencias de la aplicación, permitiéndonos configurar qué versión de cada librería utilizar.

Comunicados de servicio independientes

Dado que el repositorio solo contiene el código de algún servicio y nada más, puedes tener tu propio ciclo de despliegue, independientemente de los avances de las aplicaciones que acceden a él.

El servicio puede utilizar un ciclo de liberación rápido, como la entrega continua (donde el nuevo código se despliega después de pasar todas las pruebas). Algunas bibliotecas que acceden al servicio pueden utilizar un ciclo de lanzamiento más lento, como las que solo producen una nueva versión una vez a la semana.

Ayuda a definir el control de acceso en toda la organización

Solo los miembros del equipo implicados en el desarrollo de una librería necesitan añadirse al repositorio correspondiente y descargar su código. Como resultado, hay una estrategia implícita de control de acceso para cada capa de la aplicación. Aquellos involucrados con la biblioteca tendrán derechos de edición, y todos los demás pueden no tener acceso al repositorio. O puede que se les den derechos de lectura pero no de edición.

Permite a los equipos trabajar de forma autónoma

Los miembros del equipo pueden diseñar la arquitectura de la biblioteca e implementar su código trabajando de forma aislada de todos los demás equipos. Pueden tomar decisiones basadas en lo que hace la biblioteca en el contexto general sin verse afectados por los requisitos específicos de algún equipo o aplicación externa.

Problemas con el enfoque Multir-Repo

El uso de múltiples repositorios puede dar lugar a varios problemas.

Las bibliotecas deben resintonizarse constantemente

Cuando se publique una nueva versión de una biblioteca que contenga cambios de ruptura, las bibliotecas que dependan de ella tendrán que adaptarse para empezar a utilizar la última versión. Si el ciclo de publicación de la biblioteca es más rápido que el de sus bibliotecas dependientes, éstas podrían quedar rápidamente desincronizadas entre sí.

Los equipos tendrán que ponerse al día constantemente para utilizar las últimas versiones de otros equipos. Dado que los distintos equipos tienen diferentes prioridades, esto puede resultar a veces arduo de conseguir.

En consecuencia, un equipo que no sea capaz de ponerse al día puede acabar ciñéndose a la versión anticuada de la biblioteca de la que depende. Este resultado tendrá implicaciones en la aplicación (en términos de seguridad, velocidad y otras consideraciones), y la brecha en el desarrollo a través de las bibliotecas solo puede aumentar.

Puede fragmentar los equipos

Cuando los diferentes equipos no necesitan interactuar, pueden trabajar en sus propios silos. A largo plazo, esto puede dar lugar a que los equipos produzcan sus subculturas dentro de la empresa, como el empleo de diferentes metodologías de programación o gestión o la utilización de diferentes conjuntos de herramientas de desarrollo.

Si algún miembro del equipo tiene que trabajar finalmente en un equipo diferente, puede sufrir un pequeño choque cultural y aprender una nueva forma de hacer su trabajo.

Monorepo vs Multi-Repo: Principales diferencias

Ambos enfoques se ocupan, en última instancia, del mismo objetivo: gestionar el código base. Por lo tanto, ambos deben resolver los mismos retos, como la gestión de las versiones, el fomento de la colaboración entre los miembros del equipo, la gestión de los problemas y la ejecución de las pruebas, entre otros.

Su principal diferencia radica en el momento en que los miembros del equipo deben tomar decisiones: por adelantado en el caso de los monorepos o por debajo de la línea en el caso de los multi-repos.

Analicemos esta idea con más detalle.

Dado que todas las bibliotecas se versionan de forma independiente en el multi-repo, un equipo que libere una biblioteca con cambios de ruptura puede hacerlo de forma segura asignando un nuevo número de versión principal a la última versión. Otros grupos pueden hacer que sus bibliotecas dependientes se ciñan a la versión antigua y cambien a la nueva una vez adaptado su código.

Este enfoque deja la decisión de cuándo adaptar todas las demás bibliotecas a cada equipo responsable, que puede hacerlo en cualquier momento. Si lo hacen demasiado tarde y se publican nuevas versiones de las bibliotecas, cerrar la brecha entre ellas será cada vez más difícil.

En consecuencia, mientras que un equipo puede iterar rápidamente y con frecuencia en su código, otros equipos pueden resultar incapaces de ponerse al día, produciendo finalmente bibliotecas divergentes.

Por otro lado, en un entorno monorepo, no podemos liberar una nueva versión de una biblioteca que rompa alguna otra biblioteca, ya que tus pruebas fallarán. En este caso, el primer equipo debe comunicarse con el segundo para incorporar los cambios.

Este enfoque obliga a los equipos a adaptar todas las bibliotecas en conjunto cada vez que haya que hacer un cambio en una sola biblioteca. Todos los equipos se ven obligados a hablar entre sí y llegar a una solución conjunta.

Como resultado, el primer equipo no podrá iterar tan rápido como desea, pero el código de las diferentes bibliotecas no empezará a divergir en ningún momento.

En resumen, el enfoque multi-repo puede ayudar a crear una cultura de «moverse rápido y romper cosas» entre los equipos, donde los equipos ágiles e independientes pueden producir sus resultados a su velocidad. En cambio, el enfoque monorrepo favorece una cultura de concienciación y cuidado, en la que los equipos no deben quedarse atrás para resolver un problema por sí solos.

Enfoque híbrido Poly-As-Mono

Si no podemos decidir si utilizar el enfoque multi-repo o monorepo, también existe el enfoque intermedio: utilizar múltiples repositorios y emplear alguna herramienta para mantenerlos sincronizados, asemejándose a un monorepo pero con más flexibilidad.

Meta es una de esas herramientas. Organiza múltiples repositorios en subdirectorios y proporciona una interfaz de línea de comandos que ejecuta el mismo comando en todos ellos simultáneamente.

Un meta-repositorio contiene la información sobre los repositorios que componen un proyecto. La clonación de este repositorio a través del meta-repositorio clonará recursivamente todos los repositorios necesarios, facilitando que los nuevos miembros del equipo puedan empezar a trabajar en sus proyectos inmediatamente.

Para clonar un meta-repositorio y todos tus repositorios múltiples definidos, debemos ejecutar lo siguiente:

meta git clone [meta repo url]

Meta ejecutará un git clone para cada repositorio y lo colocará en una subcarpeta:

Clonación de un metaproyecto.
Clonación de un metaproyecto. (Fuente de la imagen: github.com/mateodelnorte/meta)

A partir de ahí, al ejecutar el comando meta exec se ejecutará el comando en cada subcarpeta. Por ejemplo, ejecutar git checkout master en cada repositorio se hace así:

meta exec "git checkout master"

Enfoque híbrido Mono-As-Poly

Otro enfoque es gestionar el código a través de un monorepo para el desarrollo, pero copiando el código de cada biblioteca en tu repositorio independiente para el despliegue.

Esta estrategia es frecuente en el ecosistema PHP porque Packagist (el repositorio principal de Composer) requiere una URL de repositorio público para publicar un paquete, y no es posible indicar que el paquete se encuentra dentro de un subdirectorio del repositorio.

Dada la limitación de Packagist, los proyectos de PHP pueden seguir utilizando un monorepo para el desarrollo, pero deben utilizar el enfoque multi-repo para el despliegue.

Para lograr esta conversión, podemos ejecutar un script con git subtree split o utilizar una de las herramientas disponibles que realizan la misma lógica:

¿Quién utiliza Monorepo frente a Multi-Repo?

Varias grandes empresas tecnológicas se decantan por el método monorrepo, mientras que otras han decidido utilizar el método multirrepo.

Google, Facebook, Twitter y Uber han respaldado públicamente el enfoque de los monorrepos. Microsoft gestiona el mayor monorepo Git del planeta para alojar el código fuente del sistema operativo Windows.

En el lado opuesto, Netflix, Amazon y Lyft son empresas famosas que utilizan el enfoque de múltiples reposiciones.

En el lado híbrido poli-as-mono, Android actualiza múltiples repositorios, que se gestionan como un monorepo.

En el lado híbrido mono-as-poly, Symfony mantiene el código de todos sus componentes en un monorepo. Lo dividen en repositorios independientes para el despliegue (como symfony/dependency-injectionsymfony/event-dispatcher.)

Ejemplos de Monorepo y Multi-Repo

La cuenta de WordPress en GitHub alberga ejemplos de los enfoques monorepo y multirrepo.

Gutenberg, el editor de bloques de WordPress, se compone de varias docenas de paquetes JavaScript. Estos paquetes están todos alojados en el monorepo WordPress/gutenberg y gestionados a través de Lerna para ayudar a publicarlos en el repositorio npm.

Openverse, el motor de búsqueda de medios con licencia abierta, aloja sus partes principales en repositorios independientes: Front-end, Catálogo y API.

Monorepo vs Multi-Repo: ¿Cómo elegir?

Como ocurre con muchos problemas de desarrollo, no hay una respuesta predefinida sobre el enfoque que debe utilizarse. Diferentes empresas y proyectos se beneficiarán de una estrategia u otra en función de sus condiciones únicas, como por ejemplo:

  • ¿Qué tamaño tiene el código base? ¿Contiene gigabytes de datos?
  • ¿Cuántas personas trabajarán en el código base? ¿Son 10, 100 o 1.000?
  • ¿Cuántos paquetes habrá? ¿Son unos 10, 100 o 1.000?
  • ¿En cuántos paquetes tiene que trabajar el equipo en un momento dado?
  • ¿Qué grado de acoplamiento tienen los paquetes?
  • ¿Se trata de diferentes lenguajes de programación? ¿Requiere la instalación de un software concreto o un hardware especial para funcionar?
  • ¿Cuántas herramientas de despliegue se necesitan y qué complejidad tienen a la hora de configurarlas?
  • ¿Cuál es la cultura de la empresa? ¿Se anima a los equipos a colaborar?
  • ¿Qué herramientas y tecnologías saben utilizar los equipos?

Resumen

Existen dos estrategias principales para alojar y gestionar el código: monorepo y multirepo. El enfoque monorepo implica almacenar el código de diferentes bibliotecas o proyectos -e incluso todo el código de una empresa- en un único repositorio. Y el sistema multi-repo divide el código en unidades, como bibliotecas o servicios, y mantiene su código alojado en repositorios independientes.

El enfoque a utilizar depende de una multitud de condiciones. Ambas estrategias tienen varias ventajas y desventajas, y acabamos de cubrir todas ellas en detalle en este artículo.

¿Te queda alguna duda sobre los monorrepos o los multirrepos? ¡Háznoslo saber en la sección de comentarios!

Leonardo Losoviz

Leo writes about innovative web development trends, mostly concerning PHP, WordPress and GraphQL. You can find him at leoloso.com and twitter.com/losoviz.