Mono-repositorios: por favor no

Del traductor: ¡Hola, Habr! Sí, este es otro artículo sobre las ventajas y desventajas de los monorepositorios. Iba a escribir mi artículo sobre cómo usamos el mono-repositorio, cómo cambiamos de maven a bazel y lo que surgió de él. Pero mientras lo pensaba, salió un excelente artículo del desarrollador de Lyft, que decidí traducir para usted. Prometo publicar mis adiciones al artículo, así como la experiencia con bazel como secuela.
Estamos en el nuevo año 2019, y estoy listo para otra discusión sobre las ventajas (o la falta de ellas) en el almacenamiento de todo el código fuente de la organización en el "Monorepository". Para aquellos de ustedes que no están familiarizados con este enfoque, la idea es almacenar todo el código fuente en un único repositorio del sistema de control de versiones. Una alternativa, por supuesto, es almacenar el código fuente en varios repositorios independientes, generalmente dividiéndolos a lo largo de la frontera de servicios / aplicaciones / bibliotecas.

En esta publicación, llamaré a este enfoque "polirrepositorio".

Algunos de los gigantes de TI usan mono-repositorios, incluidos Google, Facebook, Twitter y otros. Por supuesto, si tales compañías de buena reputación usan mono-repositorios, entonces los beneficios de este enfoque deberían ser enormes, y todos deberíamos hacer lo mismo, ¿verdad? No! Como dice el título del artículo: "¡No utilices el mono-repositorio!" Por qué Porque a gran escala, el monorrepositivo resolverá los mismos problemas que resuelve el polirrepositorio, pero al mismo tiempo provoca la gran coherencia de su código y requiere esfuerzos increíbles para aumentar la escalabilidad de su sistema de control de versiones .

Por lo tanto, a mediano y largo plazo, el mono-repositorio no proporciona ninguna ventaja organizativa, mientras que deja a los mejores ingenieros de la compañía con el síndrome postraumático (manifestado en forma de babeo y murmullos incoherentes sobre el rendimiento git).


Digresión corta: ¿qué quiero decir con "a gran escala"? No hay una respuesta única a esta pregunta, sino porque Estoy seguro de que me preguntas sobre esto, digamos que hay unos 100 desarrolladores que escriben código a tiempo completo.

Ventajas teóricas de un monorepositivo y por qué no se pueden lograr sin las herramientas que se utilizan para poliresitorios (o falsos)


Ventaja teórica 1: colaboración y código compartido más fáciles


Los defensores de los mono-repositorios afirman que cuando todo el código está en el mismo repositorio, la probabilidad de duplicación del código es menor, y es más probable que diferentes equipos trabajen juntos en una infraestructura común.

Aquí está la amarga verdad sobre incluso los mono-repositorios medianos (y esto sonará constantemente en esta sección): rápidamente no resulta práctico para un desarrollador mantener todo el código del repositorio en su estación de trabajo o buscar en la base de código completa utilizando utilidades como grep. Por lo tanto, cualquier repositorio mono que quiera escalar debe proporcionar 2 cosas:

1) algo así como un sistema de archivos virtual que le permite almacenar localmente solo una parte del código. Esto se puede lograr utilizando un sistema de archivos propietario como Perforce , que admite este modo de forma nativa, utilizando la herramienta G3 interna de Google o el GVFS de Microsoft.

2) herramientas sofisticadas como servicio (como servicio) para indexar / buscar / ver el código fuente. Porque ninguno de los desarrolladores almacenará todo el código fuente en su estación de trabajo en un estado de búsqueda, se vuelve crítico poder realizar dicha búsqueda en toda la base de código.

Basado en el hecho de que el desarrollador tendrá acceso a solo una pequeña porción del código fuente en un momento dado, ¿hay al menos alguna diferencia entre descargar una parte del mono-repositorio o descargar varios repositorios independientes? No hay diferencia

En el contexto de la indexación / búsqueda / exploración y código similar, una herramienta tan hipotética puede buscar fácilmente en varios repositorios y combinar el resultado. De hecho, así es exactamente cómo funciona la búsqueda en GitHub, así como herramientas de búsqueda e indexación más sofisticadas como Sourcegraph .

Por lo tanto, desde el punto de vista del trabajo colaborativo en el código a gran escala, los desarrolladores se ven obligados en cualquier caso a trabajar solo con parte de la base del código y utilizar herramientas de nivel superior. No importa si el código se almacena en un mono-repositorio o en varios repositorios independientes, el problema se resuelve de la misma manera y la eficacia de trabajar juntos en el código depende solo de la cultura de ingeniería y no de la forma en que se almacenan los códigos fuente .

Ventaja teórica 2: una asamblea / sin gestión de dependencias


El siguiente argumento, generalmente citado por los defensores de los mono-repositorios, es que almacenar todo el código en un solo mono-repositorio le priva de la necesidad de administrar dependencias, como Todo el código se recopila al mismo tiempo. Esto es una mentira! A gran escala, simplemente no hay forma de reconstruir todo el código fuente y ejecutar todas las pruebas automatizadas cada vez que alguien realiza cambios en el sistema de control de versiones (o, lo que es más importante, más a menudo, en el servidor CI cuando se crea una nueva rama o solicitud de extracción). Para resolver este problema, todos los grandes repositorios mono utilizan su sofisticado sistema de compilación (por ejemplo, Bazel / Blaze de Google o Buck de Facebook), que está diseñado para monitorear los cambios y sus bloques dependientes y construir un gráfico de dependencia del código fuente. Este gráfico le permite organizar el almacenamiento en caché eficiente de resultados y pruebas de ensamblaje, por lo que solo los cambios y sus dependencias necesitan reensamblado y prueba.

Además, desde el código recopilado eventualmente debería implementarse y, como usted sabe, no se puede implementar todo el software a la vez, es importante que todos los artefactos de ensamblaje estén controlados, de modo que los artefactos se vuelvan a hacer según sea necesario. En esencia, esto significa que incluso en el mundo de los mono-repositorios, pueden existir varias versiones del código al mismo tiempo en la naturaleza, y deben ser monitoreadas y coordinadas cuidadosamente.

Los defensores del mono-repositorio también argumentarán que incluso con la necesidad de rastrear ensambles / dependencias, esto todavía ofrece una ventaja innegable, ya que un solo commit describe el estado completo del mundo entero. Diría que esta ventaja es bastante controvertida, dado que el gráfico de dependencia ya existe, y parece una tarea bastante trivial incluir el identificador de confirmación para cada repositorio independiente como parte de este gráfico, y de hecho Bazel puede trabajar fácilmente con varios repositorios independientes, así como con uno mono-repositorio, abstrayendo el nivel subyacente del desarrollador. Además, es fácil implementar tales herramientas de refactorización automatizadas que actualizan automáticamente las versiones de bibliotecas dependientes en varios repositorios independientes a la vez, nivelando la diferencia entre el monorepository y polyrepository en esta parte (más sobre esto más adelante).

El resultado final es que las realidades de ensamblaje / despliegue a gran escala son, en su mayor parte, las mismas para mono-repositorios y polirrepositorios. No hay diferencia para las herramientas, no debería ser para desarrolladores que escriben código .

Ventaja teórica 3: la refactorización de código es una confirmación atómica simple


Finalmente, la última virtud que mencionan los defensores de los mono-repositorios es el hecho de que un repositorio simplifica la refactorización del código debido a la facilidad de búsqueda, y la idea de que una sola confirmación puede abarcar todo el repositorio. Esto no es cierto por varias razones:

1) como se describió anteriormente, a gran escala, el desarrollador no podrá editar o buscar la base del código completo en su máquina local. Por lo tanto, la idea de que cualquiera puede clonar fácilmente todo su repositorio y simplemente hacer grep / replace no es tan fácil de poner en práctica.

2) incluso si suponemos que con la ayuda de un complejo sistema de archivos virtual un desarrollador puede clonar y editar la base de código completa, ¿con qué frecuencia ocurrirá esto? No estoy hablando de corregir un error en la implementación de una biblioteca compartida, porque esta situación se maneja igualmente en el caso de un repositorio único y en el caso de un repositorio múltiple (suponiendo un sistema de compilación / implementación similar, como se describió anteriormente). Estoy hablando de cambiar la API de la biblioteca, que será seguida por muchos errores de compilación en los lugares donde se llama a esta biblioteca. En una base de código muy grande, es casi imposible hacer un cambio en la API básica, que será vista previamente por todos los equipos involucrados antes de que los conflictos de fusión lo obliguen a comenzar el proceso nuevamente . El desarrollador tiene 2 posibilidades reales: puede darse por vencido y encontrar una solución para el problema con la API (en la práctica, esto sucede con más frecuencia de lo que a todos nos gustaría), o puede desviar la API existente, escribir una nueva API y luego embarcarse en el largo y actualizar minuciosamente todas las llamadas a la antigua API en toda la base del código. En cualquier caso, este es absolutamente el mismo proceso que con el polirrepositorio .

3) en un mundo orientado a servicios, las aplicaciones consisten en muchos componentes poco acoplados que interactúan entre sí utilizando algún tipo de API bien descrita. Las organizaciones más grandes, tarde o temprano, cambiarán a usar IDL (lenguaje de descripción de interfaz), como Thrift o Protobuf, que le permiten realizar API de tipo seguro y realizar cambios compatibles con versiones anteriores. Como se describió en la sección anterior sobre ensamblaje / implementación, el código no se puede implementar simultáneamente . Se puede implementar durante un período de tiempo: horas, días o incluso meses. Por lo tanto, los desarrolladores deben pensar en la compatibilidad con versiones anteriores de sus cambios. Esta es la realidad del desarrollo de software moderno, que a muchos les gustaría ignorar, pero no pueden. Por lo tanto, cuando se trata de servicios (a diferencia de las bibliotecas API), los desarrolladores deben usar uno de los dos enfoques descritos anteriormente (no cambien la API ni pasen por el ciclo de desaprobación) y esto es absolutamente lo mismo tanto para el monorepository como para el polyrepository .

Hablando de la refactorización de bases de código grandes, muchas organizaciones grandes están desarrollando sus propias herramientas de refactorización automatizadas, como fastmod , recientemente lanzada por Facebook. Como siempre, esta herramienta podría funcionar fácilmente con un repositorio o varios independientes. Lyft tiene una herramienta llamada "refactorizador" que hace exactamente eso. Funciona como fastmod, pero automatiza los cambios en varios de nuestros repositorios, incluida la creación de solicitudes de extracción, el seguimiento de estados de revisiones, etc.

Desventajas únicas de los monorepositorios


En la sección anterior, enumeré todas las ventajas teóricas que proporciona un monorepository, y noté que para aprovecharlas, es necesario crear herramientas increíblemente complejas que no difieran de las de los polirrepositorios. En esta sección, mencionaré 2 desventajas únicas de los mono-repositorios.

Desventaja 1: fuerte conectividad y software de código abierto


Organizacionalmente, un monorepository provoca la creación de software estrechamente acoplado y frágil. Les da a los desarrolladores la sensación de que pueden corregir fácilmente los errores en las abstracciones, aunque en realidad no pueden debido al inestable proceso de ensamblaje / implementación y a los factores humanos / organizacionales / culturales que surgen al intentar realizar cambios de inmediato en toda la base del código.

La estructura del código en los polirrepositorios representa límites claros y transparentes entre los equipos / proyectos / abstracciones / propietarios del código y obliga al desarrollador a considerar cuidadosamente la interfaz de interacción. Esta es una ventaja sutil, pero muy importante: hace que los desarrolladores piensen de manera más amplia y a largo plazo. Además, el uso de repositorios múltiples no significa que los desarrolladores no puedan ir más allá de los límites del repositorio. Ya sea que esto suceda o no, depende solo de la cultura de desarrollo y no de si se utiliza un monorepository o polyrepository.

La unión fuerte también tiene serias consecuencias con respecto a la apertura de su código fuente. Si una empresa quiere crear o consumir software de código abierto, el uso de múltiples repositorios es imprescindible. Las distorsiones que ocurren cuando una empresa intenta diseñar su proyecto en código abierto desde su repositorio mono (importación / exportación de códigos fuente, rastreador de errores público / privado, capas adicionales para abstraer la diferencia en bibliotecas estándar, etc.) no conducen a una colaboración productiva y construyendo una comunidad así como creando gastos generales significativos.

Defecto 2: escalabilidad del sistema de control de versiones



Escalar un sistema de control de versiones para cientos de desarrolladores, cientos de millones de líneas de código y una gran cantidad de confirmaciones es una tarea monumental. El mono repositorio de Twitter, creado hace 5 años (basado en git), fue uno de los proyectos más inútiles que he visto en mi carrera. Ejecutar un comando simple como el git status tomó minutos . Si la copia local del repositorio era demasiado antigua, la actualización podría llevar horas (en ese momento, incluso era una práctica enviar discos duros con una copia del repositorio a los empleados remotos con la última versión del código). Recuerdo esto no para burlarse de los desarrolladores de Twitter, sino para ilustrar cuán complejo es este problema. Puedo decir que 5 años después, el rendimiento del mono-repositorio de Twitter aún está lejos del que a los desarrolladores del equipo de Tilling les gustaría ver, y esto no es porque se hayan esforzado mucho.

Por supuesto, en los últimos 5 años, se ha producido algún desarrollo en esta área. El Git VFS de Microsoft, que se usa para desarrollar Windows, ha llevado a la aparición de un sistema de archivos virtual real para git, que describí anteriormente como un requisito previo para escalar un sistema de control de versiones (y con la compra de Microsoft Github parece que este nivel de escalado encontrará su aplicación en las características que GiHub ofrece a sus clientes corporativos). Y, por supuesto, Google y Facebook continúan invirtiendo enormes recursos en sus sistemas internos para que continúen funcionando, aunque casi nada de esto está disponible públicamente.

Entonces, ¿por qué necesita resolver generalmente estos problemas al escalar el sistema de control de versiones, si, como se describe en la sección anterior, se requiere que el kit de herramientas sea exactamente el mismo que para el multirepository? No hay una razón razonable para esto.

Conclusión


Como sucede a menudo en el desarrollo de software, miramos a las compañías de software más exitosas como un ejemplo y tratamos de tomar prestadas sus mejores prácticas sin comprender qué es exactamente lo que llevó a estas compañías al éxito. Los monorepositorios, en mi opinión, son un ejemplo típico de tal caso. Google, Facebook y Twitter han invertido una gran cantidad de recursos en sus sistemas de almacenamiento de código solo para encontrar una solución que sea esencialmente la misma que la requerida para un repositorio múltiple, pero que provoca un fuerte vínculo y requiere una gran inversión en el control de la versión de escala .

De hecho, a gran escala, cómo trabaja una empresa trabajando junto con el código, la colaboración, la unión fuerte, etc. depende directamente de la cultura de ingeniería y el liderazgo, y no tiene que ver con si se usa un monorepository o polypository . Ambas soluciones se ven iguales para el desarrollador. Entonces, ¿por qué usar un monorepository? Por favor no!

Source: https://habr.com/ru/post/es435306/


All Articles