15 puntos por GN⁺ 2025-06-05 | 4 comentarios | Compartir por WhatsApp
  • Adoptar un monorepo ofrece ventajas como consistencia organizacional, reutilización de código y un entorno de herramientas compartido más sólido, pero si se copian tal cual los casos de las grandes tecnológicas, se termina enfrentando nuevos problemas y desafíos
  • Para que un monorepo tenga éxito, hay que seguir el principio de que todas las tareas principales sean O(change) y no O(repo), y en cada etapa de build, pruebas y CI/CD se necesitan herramientas y estrategias alineadas con eso
  • En control de código fuente, se puede empezar con git, pero a medida que aumenta la escala conviene considerar una expansión gradual con sparse checkout y sistemas de archivos virtuales
  • En el sistema de build, se recomienda mantener un solo lenguaje siempre que sea posible, aguantar lo más posible con las herramientas de build nativas de cada lenguaje, y migrar gradualmente a Bazel/Buck2 solo cuando sea realmente necesario
  • En pruebas y CI/CD, hay que detectar rápido solo el alcance afectado por los cambios para hacer build, probar y desplegar; en monorepos grandes también son esenciales estrategias de confiabilidad como reintentos automáticos y aislamiento de pruebas flaky

Introducción: el inicio del camino hacia el monorepo

  • Si eres ingeniero en un nuevo equipo de Developer Productivity, es natural preguntarte qué preparación y esfuerzo hacen falta después de decidir adoptar un monorepo
  • Las mejores prácticas de empresas grandes como Google, Meta y Uber se ven impresionantes, pero en la práctica es imposible lograr exactamente el mismo nivel de resultados que ellas
  • Cada organización debe decidir adoptar un monorepo según sus propias razones y necesidades, y en ese proceso puede buscar ventajas en consistencia, integración organizacional y herramientas compartidas, entre otras

Aclarar por qué hace falta un monorepo

  • Los casos de grandes empresas son, en realidad, el estado al que llegaron como resultado final, por lo que no son una referencia adecuada para las etapas iniciales
  • En la práctica surgen problemas nuevos, y aparecen tipos de issues distintos a los de administrar varios repositorios por separado
  • El objetivo de adoptar un monorepo está en mantener la consistencia, unificar herramientas en toda la organización y aplicar estándares y convenciones de ingeniería
  • Cada equipo debe definir con claridad objetivos alineados con su propia cultura y dirección para obtener resultados efectivos

Regla de oro: el principio de O(change)

  • Todas las herramientas relacionadas con el repositorio deben tener complejidad O(change) y no O(repo) para poder funcionar con rapidez
  • En la práctica, cuanto más grande es un monorepo a gran escala, más se notan las ineficiencias de las herramientas existentes, por lo que es indispensable un diseño estructural que supere esos problemas de rendimiento
  • Incluso las innovaciones mencionadas en blogs técnicos de grandes empresas suelen centrarse, en su mayoría, en superar las ineficiencias causadas por O(repo)

Control de código fuente

  • La mayoría de las organizaciones de software usan Git como base, pero Git tiene límites de rendimiento cuando se escala mucho en un entorno de monorepo centralizado
    • Siendo realistas, la mayoría de las organizaciones puede aguantar bastante tiempo con git+GitHub
  • A medida que el crecimiento se acelera, se vuelven necesarias estructuras como sparse checkout (clonado parcial) y sistemas de archivos virtuales (descargar archivos dinámicamente desde el servidor cuando hagan falta)
  • Las grandes empresas hacen fork de Git o desarrollan sistemas separados para esto (Microsoft: fork propio de Git, Meta: fork de Mercurial, Google: Piper)
    • También vale la pena considerar controles de código fuente de nueva generación como Jujutsu
  • Cuando la escala todavía es pequeña, Git puede usarse sin problemas, pero durante el crecimiento conviene tener en mente una estrategia de escalado
  • También existe el problema práctico de que, si el código fuente incluye código generado a partir de IDL (Interface Definition Language), el tamaño del repositorio puede crecer de forma exponencial

Sistema de build

  • Bazel y Buck2 son herramientas representativas de build para monorepos, y soportan múltiples lenguajes y grafos de build complejos
    • Son poderosas, pero implican mucha complejidad y carga operativa
  • Si mantienes el build en un solo lenguaje, la vida se vuelve mucho más fácil, y los sistemas de build de cada lenguaje (por ejemplo: Maven, Gradle, Cargo, Go) también tienen alta escalabilidad
  • La función principal del sistema de build es “hacer build de forma eficiente del target especificado (generación eficiente de artefactos)” y “determinar rápidamente los targets afectados por archivos modificados”
  • Para esto hace falta el concepto de target determinator (herramienta de determinación de targets), y en ecosistemas como Rust, Go y Bazel ya existen varias soluciones
  • La ejecución remota y el caché solo suelen ser realmente necesarios a una escala gigantesca; en empresas comunes, target determination resulta más práctico

Pruebas

  • Como ejecutar todas las pruebas cada vez es ineficiente, se necesita un sistema que pruebe solo el alcance impactado por los cambios
  • Las pruebas flaky pueden convertirse en un problema todavía más serio en sistemas de pruebas a gran escala
  • Un sistema de pruebas necesita reintentos automáticos, determinación automática del alcance afectado por las pruebas y aislamiento de pruebas flaky
  • Algunos lenguajes (por ejemplo, Rust con nextest y Java con JUnit) ofrecen estas funciones avanzadas de forma nativa o mediante extensiones
  • Para que funcione bien, el esquema de pruebas de un monorepo debe integrarse estrechamente con el sistema de build

Integración continua (CI)

  • Un sistema de CI debe ejecutar automáticamente los artefactos de build y las validaciones necesarias según los cambios realizados
  • El rendimiento y la eficiencia del target determinator actúan como un elemento central del pipeline de CI
  • El CI moderno usa varias estrategias, como Merge Queue, para encontrar un equilibrio entre mantener la calidad del código y optimizar la velocidad de merge
    • Por ejemplo, decidir si ejecutar todas las validaciones en cada commit/PR, seleccionar solo algunas o procesar varios PR en lote
  • Hay que definir y diseñar internamente los trade-offs entre throughput, correctness y tail latency
  • La gestión de merges y la mejora de la eficiencia del CI en monorepos grandes sigue siendo un desafío sin una solución perfecta
  • Rust (bors), Chromium y Uber eligen estrategias distintas de merge y validación

Despliegue continuo (CD)

  • La ilusión de que todos los cambios dentro de un monorepo se desplegarán de forma atómica no coincide con la realidad
  • En un solo PR se pueden cambiar a la vez la interfaz, la implementación y hasta los clientes de varios servicios, pero al final el despliegue real ocurre de manera asíncrona, por lo que pueden aparecer problemas al momento de desplegar
  • Los cambios que rompen contratos entre servicios pueden provocar incidentes graves durante el despliegue
  • Una estrategia efectiva de CD para monorepos necesita considerar los ciclos del sistema de despliegue, la validación de contratos entre servicios y la capacidad de detectar y responder rápido cuando surge un problema

Conclusión

  • El monorepo es una herramienta poderosa para fortalecer la consistencia organizacional y la cultura de ingeniería, pero requiere inversión continua en ingeniería y herramientas
  • En cada etapa, la clave es construir automatización, herramientas y cultura alineadas con el principio de O(change)
  • A medida que la organización crece, también hay que hacer evolucionar las herramientas de forma continua, y es importante un esfuerzo de gestión sistemático que refleje los objetivos y la cultura de la organización
  • Si hay suficiente determinación, compromiso e inversión sostenida, un monorepo termina generando un valor que justifica todo eso

4 comentarios

 
bichi 2025-06-05

Es un artículo muy sustancioso. No solo hacen falta herramientas potentes, también hay que estar dispuesto a crear las herramientas necesarias cuando haga falta. Por eso, si todo funciona bien, también se obtienen muchos beneficios.

 
cosine20 2025-06-05

Cuando estaba en la maestría, una vez mi asesor volvió de una comida con un ingeniero que había trabajado en Google y, no sé si porque escuchó hablar de monorepos, propuso que nosotros también los administráramos así en adelante; me costó bastante convencerlo de que no lo hiciéramos...
Aunque los monorepos tienen muchas ventajas, en nuestro laboratorio, por su naturaleza, era frecuente tener que compartir los resultados con personas externas, y si hubiéramos gestionado esos resultados en un monorepo, creo que habríamos sufrido bastante justo por eso. Con un multirepo, en cambio, simplemente puedes ajustar el alcance de publicación para cada resultado.

 
youngrok 2025-06-05

Creo que la mayoría de las veces que uno sufre con un monorepo es porque ya fragmentó demasiado el proyecto desde antes. Tomas un proyecto que originalmente pudo haber sido uno o dos y lo divides en unos 10; luego intentas integrarlo y gestionarlo con un monorepo, así que terminas necesitando también herramientas de gestión de monorepos y la complejidad sube. Es mejor simplemente integrar el proyecto en uno o dos, y aunque sean dos o más proyectos, en vez de usar una herramienta de gestión aparte, pensar solo en separarlos por directorios y ponerlos en un solo repositorio hace que sea mucho más fácil de administrar.

 
GN⁺ 2025-06-05
Opinión de Hacker News
  • Al ver este hilo, piden compartir experiencias que recuerdan a aquellas historias sobre los complexity merchants de antes. Hay quien no está nada de acuerdo con la idea de que moverse a un monorepo implique sacrificios técnicos. Si entiendes el poder de un sistema de archivos jerárquico, entiendes el valor del monorepo. También es mucho más claro tener CI/CD configurado en un solo monorepo que en configuraciones dispersas por todos lados. La clave del monorepo es que toda la organización puede hacer commits atómicos. Al coordinar a muchos desarrolladores, su utilidad es abrumadora. Basta con hacer rebase una vez y tener una sola reunión grande. Aunque los miembros del equipo no se lleven bien ni colaboren entre sí, desde la gestión el monorepo también funciona como una gran herramienta de RR. HH.

    • Últimamente los desarrolladores tienden demasiado a separar todo, a los microservicios, a muchos repositorios pequeños y a evitar al extremo los monolitos. Eso termina aumentando la complejidad y convirtiendo problemas de estructura organizacional en futuros problemas técnicos. Tampoco se reconocen bien las dependencias internas de los sistemas de software. Es increíble cuánto tiempo se desperdiciaba en mi trabajo anterior solo para actualizar archivos de esquema de Protocol Buffers. Por suerte, en mi empresa actual no pasa eso.

    • Rastrear commits entre varios proyectos es algo bueno de tener, pero en la práctica no marca una gran diferencia en seguimiento de dependencias ni al disparar pruebas downstream. También se puede lograr perfectamente con automatización multirepo. El monorepo ayuda, pero no es completo y además tiene costos altos. Los despliegues o builds no se procesan de forma atómica. Cuando el monorepo crece demasiado, hay que salir de git y adoptar herramientas nuevas, y eso es un trabajo enorme. No es algo sobre lo que se pueda hablar a la ligera sin haberlo vivido.

    • Las ventajas del monorepo existen claramente, pero el costo de administración es más alto que el de un polyrepo. No significa que el monorepo sea siempre la mejor opción en cualquier situación. Para una explicación detallada, véase este artículo. La relación costo-beneficio depende del contexto.

    • Una regla empírica útil al diseñar entornos de programación es que mientras más poder se le da al equipo, más problemas aparecen. Técnicamente, los commits atómicos no son un poder más fuerte sino más bien uno más limitado, pero al permitir trabajar con interfaces malas, terminan siendo un tipo de poder que provoca problemas.

    • Hay quien opina que creer que los cambios se vuelven más atómicos al pasarse a un monorepo es una trampa. [Cita del original: la mayor ilusión del monorepo es que permite commits atómicos sobre toda la base de código. En realidad existen distintos artefactos de despliegue, y aunque cambies servicios y clientes al mismo tiempo, el despliegue ocurre de forma asíncrona. Con varios repos hay que trabajar con varios PR, así que el riesgo se percibe desde el inicio. El CI del monorepo suele servir para validar contratos de servicio (jobs de CI), y cuando hace falta se exige documentar el motivo del cambio.]

  • En los monorepos de Big Tech hay dos tipos. El primero es el único monorepo corporativo, el "THE" monorepo del que habla el artículo, que requiere VCS/CI personalizados y cuenta con soporte de 200 ingenieros. Google, Meta y Uber trabajan así. El sufrimiento para llegar a ese nivel va mucho más allá de lo imaginable, y normalmente se empieza por monorepos más pequeños “por equipo” que luego se van ampliando gradualmente. Cada stack/lenguaje/equipo lo gestiona por su cuenta con herramientas como Bazel, Turborepo o Poetry, y con el tiempo todo se fusiona en un monorepo más grande. Pero en ambos casos hay inversiones de millones de dólares y millones de horas tanto de desarrolladores como del negocio, y al final se mantiene gracias al soporte de quienes sobrevivieron ese proceso.

    • Cuando trabajé en una empresa con un monorepo grande, lo prefería muchísimo más. Un monorepo único ayuda muchísimo a entender con transparencia el grafo de servicios, la estructura de llamadas del código y el panorama completo. En un polyrepo, el conocimiento queda disperso entre equipos, es difícil asumir código nuevo y entender el archivo histórico del código se vuelve casi una exploración de laberintos. El polyrepo se siente como viejos mensajes de Discord o Slack que nadie recuerda. Si el monorepo cuesta caro, el polyrepo también, solo que de otra forma. El monorepo es un gigantesco herbívoro continental; el polyrepo es una diversidad de especies enterradas en la oscuridad.

    • En mi empresa actual, el backend está dividido en unas 11 repos de git, y para una sola funcionalidad hacen falta 4 o 5 merge requests, lo cual es muy incómodo. Estamos considerando introducir un monorepo para reunir varios proyectos. Pero si no se pueden fusionar los repos, me pregunto cuál sería la alternativa al monorepo.

    • Aún no existe un sistema de orquestación de monorepos que sea fácil y potente sin importar el lenguaje. Bazel es complejo y difícil de aprender, aunque últimamente la documentación ha mejorado mucho. También hay otras opciones como Buck, NX y Pants, pero cada una tiene sus particularidades y, sobre todo, el soporte para web es limitado. La mayoría de los CI no soportan bien estas herramientas, así que configurarlas es complicado. Como referencia, Rush de Microsoft ofrece la mejor experiencia; especialmente para monorepos de frontend/NodeJS, recomiendo Rush sitio oficial de Rush.

    • También se menciona una realidad: la mayoría de los monorepos no crecen hasta la escala de gigantes como Google, Uber o Meta. La cantidad de servicios varía por empresa, y aunque llegues a unos 100, no suele haber problemas de escala en el VCS y las etiquetas de LSP siguen funcionando bien en una laptop. Incluso correr todas las pruebas en CI sin demasiada inteligencia suele ser bastante viable. Conclusión: no todas las empresas necesitan escala Google.

    • En mi empresa actual estamos construyendo monorepos por stack de lenguaje. Es un compromiso bastante razonable.

  • Un punto que no suele salir mucho en la discusión monorepo vs multirepo es la aparición de la “ley de Conway inversa”. Es decir, que la estructura del repo influye en la estructura organizacional y en cómo se resuelven los problemas. El monorepo tiende a provocar trabajo heroico en los equipos de infraestructura común, y al tocar áreas compartidas aumenta la posibilidad de romper cosas, así que incluso desarrollar una sola funcionalidad se vuelve más difícil. En multirepo hacen falta varios PR entre equipos, coordinación y política interna, pero también permite repartir esos roles entre más desarrolladores.

    • Incluso en un monorepo, si se trata de un cambio profundamente conectado en el centro del sistema, se puede aplicar en varias etapas. En ese proceso también hay que manejar varios PR, coordinación y temas políticos, pero precisamente por ser un monorepo se puede ver la situación del rollout con más claridad.

    • En el polyrepo es mucho más común sufrir porque los cambios en áreas comunes no se reflejan en los repos downstream, cada repo queda fijado a una versión distinta y pasan años sin actualizarse.

    • Se cuestiona si realmente es correcto asumir que la organización primero elige una dirección mediante la estructura de repos y luego las decisiones técnicas la siguen. En la práctica, antes que la estructura concreta del repo suele existir una filosofía organizacional más profunda (fragmentación vs compartición). Incluso si cambia la dirección, la forma de gestionar el código puede ajustarse después. En un multirepo, los ingenieros pueden tener acceso a casi todo el código, y en un monorepo también se pueden aplicar aislamientos fuertes y reglas separadas de CI o despliegue.

    • En un monorepo es mucho más común que se hagan cambios sencillos entre proyectos, mientras que en un polyrepo a menudo son tan engorrosos que ni siquiera se intentan.

  • Por experiencia en grandes empresas tecnológicas, para gestionar el sistema de builds hace falta directamente un equipo dedicado. Los monorepos grandes se basan en sistemas de archivos virtuales que descargan archivos fuente según se necesiten. Algo que el artículo no menciona es que casi todo el desarrollo se hace en servidores de desarrollo que corren en el datacenter, usando entornos de 50 a 100 cores o contenedores on-demand que se actualizan continuamente al commit más reciente. El IDE se integra con el dev server y la preparación/configuración automática por lenguaje o servicio también se automatiza con chef/ansible. Es muy raro desarrollar un monorepo grande directamente en una laptop (excepción: apps móviles o de Mac, etc.).

    • Probablemente alguien con experiencia en el mismo equipo de builds. Tanto si el entorno de desarrollo del monorepo es local como remoto, la reproducibilidad es más importante. Si se usan dev servers remotos basados en imágenes, es más fácil y confiable.

    • También hay experiencia usando entornos de desarrollo en datacenter incluso en equipos pequeños. Viendo el precio y la densidad del hardware actual, montar tu propio rack y correr herramientas on-demand para dev/staging/test resulta mucho más razonable. Cuando se comparte un entorno de desarrollo parecido a producción, la forma de trabajar con monorepo se ve completamente distinta. Pero las empresas pequeñas y medianas no tienen capacidad para invertir en sistemas de build, y además ni siquiera llegan a tener ese tipo de problemas de build a gran escala (incluso con equipos de 10 a 20 personas y productos muy complejos, el mantenimiento puede seguir siendo solo a tiempo parcial).

  • Historia de un equipo pequeño en Molnett (serverless cloud) que experimentó una eficiencia enorme con un monorepo basado en Bazel (1.5 personas full-time). Con Tilt+Bazel+Kind levantan toda la plataforma y hasta operadores de Kubernetes en una laptop, con soporte para Mac/Linux. Incluso pueden validar localmente un OS basado en Bottlerocket y hasta Firecracker. Construyeron una tool layer para que todos los desarrolladores usen las mismas versiones de go/kubectl, sin necesidad de instalación local. Requiere esfuerzo de mantenimiento, pero fue posible gracias a alguien ex Google SRE. Quieren seguir trabajando así para siempre. (Los lenguajes principales son Golang, Bash y Rust)

    • Siendo un equipo tan pequeño de 1.5 personas, un repo único es lo natural. Mi experiencia con Bazel fue muy mala, aunque quizá valga la pena en proyectos grandes. Para menos de 2 personas, probablemente Kind+Tilt por sí solos bastan. La tool layer también la resuelve en parte Go con go.mod. Algo similar puede hacerse con kubectl. También hay que pensar en el nivel salarial de alguien ex-Googler. Ojalá el costo de mantener Bazel siga valiendo la pena.

    • En nuestra empresa desplegamos con servicios basados en systemd y playbooks de ansible, y con tmuxinator arrancamos automáticamente backend/DB/motor de búsqueda/frontend y todos los servicios en modo dev de una sola vez en la terminal. Basta ejecutar una vez el comando tmuxinator en la raíz y todo el entorno dev queda listo. Un único monorepo es abrumadoramente más conveniente que antes.

    • Situación parecida, comparten que la adopción de Bazel maximizó mucho el efecto. Gracias a la tool layer, el entorno de desarrollo se mantiene consistente. Pero hay que usar bazel run directamente y preguntan si existe una mejor forma de automatizarlo. Piden que les expliquen cómo funciona.

    • Con un equipo de 2 personas, el patrón de microservicios/K8s en sí ya es overengineering. Con ese tamaño de equipo, cualquier enfoque funciona. Antes también funcionaban Dropbox/SVN/MS VCS o lo que fuera (había incomodidades, pero nada realmente problemático). En esta escala, todos pueden tener el proceso completo en la cabeza. La experiencia compartida es que herramientas o infraestructura complejas no son el factor del éxito.

  • Un freelancer comparte que en los últimos 4 años configuró monorepos tres veces en distintas empresas. Al limitarse al frontend y al ecosistema JavaScript/TypeScript, la gestión fue relativamente más fácil. Un buen monorepo, en la práctica, se comporta internamente como un polyrepo: cada proyecto puede desarrollarse/desplegarse/hostearse de forma independiente, pero convive dentro de una sola base de código y además puede compartir libremente componentes comunes (como UI), garantizando una apariencia y experiencia consistentes. Como guía práctica recomienda este material de referencia.

    • Esto en realidad no es un polyrepo, sino un caso de monorepo bien construido.
  • Al final, todo depende del caso. En nuestra empresa gestionamos unas 40 repos de git con CI separado; luego de build/test/packaging se genera finalmente una imagen integrada del sistema de archivos para pruebas de integración. Los componentes se comunican mediante mensajes de Flatbuffers y flatbuffers también se gestiona como submódulo. Manejar dependencias downstream sí es complicado, pero se gana cierta flexibilidad con progressive enhancement. En un caso así, incluso diagnosticar si esto es multirepo o un monorepo con muchísimos submódulos ya es ambiguo. No está claro si cambiar a monorepo traería ventajas. Al final todo se reduce a trade-offs y a elegir qué tipo de incomodidades estás dispuesto a tolerar.

  • Experiencia del autor de un blog sobre herramientas para monorepos. La gente suele enfatizar solo las ventajas del monorepo, pero en la práctica la complejidad de operar un monorepo exitoso casi siempre la absorben en segundo plano los equipos de devops/devtools. Por eso la adopción debe hacerse con cuidado, aunque si está bien construido puede aportar suficiente valor.

  • La experiencia de un monorepo bien gestionado es tan buena que no dan ganas de volver a otros workflows. Pero el enfoque improvisado de “nosotros también hagamos monorepo” sin preparación es una pesadilla. Si alguien vendiera como paquete un entorno y herramientas de monorepo ya preparados, creen que habría una gran oportunidad de negocio.

    • NX ya hace justamente ese negocio. En una startup anterior desarrollaron desde el principio con NX y con un equipo de I+D de 15 personas lograron una estandarización equivalente a la de una organización de 100 personas. En la nueva empresa (que adquirió la startup), el intento desordenado de “nosotros también monorepo” fue un desastre. Ahora están migrando a NX y está dando muy buenos resultados.
  • En organizaciones grandes, también se ha vivido que el monorepo puede, paradójicamente, limitar al extremo las dependencias entre equipos y reducir la reutilización de código. Si el equipo de librerías quiere cambiar algo, todos los consumidores aguas abajo tienen que actualizarse, pero como otros equipos la usan de formas inesperadas, el cambio se complica mucho (Hyrum's Law). Al final, las grandes empresas terminan recurriendo a copiar y pegar internamente, forks, control de acceso estricto y aprobación lenta de cambios.

    • Cuando se crea una librería pensada para uso general, hay que diseñar la API con mucho cuidado. Si es posible, no conviene cambiar la API; y si hay que hacerlo, se recomienda planificar bien un cambio grande o reemplazarla con una función nueva y dejar la versión vieja como deprecated. Si es código pequeño, copiar y pegar también puede estar bien.

    • Aun así, la ventaja del monorepo es que permite encontrar fácilmente todos los lugares donde se usa algo y, si hace falta, cambiarlo o corregirlo de forma atómica.

    • Todo software debe tener en cuenta las dependencias, y en un monorepo aumenta el poder de cambiar tanto las librerías como sus usuarios.

    • En un monorepo es más fácil modificar el código según tu necesidad, así que la probabilidad de reutilización es más alta que en un polyrepo.