Do tradutor: Olá, Habr! Sim, este é outro artigo sobre as vantagens e desvantagens dos monorepositórios. Eu ia escrever meu artigo sobre como usamos o mono-repositório, como mudamos de maven para bazel e o que resultou dele. Mas enquanto eu pensava nisso, saiu um excelente artigo do desenvolvedor da Lyft, que eu decidi traduzir para você. Prometo publicar minhas adições ao artigo, bem como a experiência com o bazel como sequência.
Estamos no novo ano de 2019 e estou pronto para outra discussão sobre as vantagens (ou a falta dela) em armazenar todo o código-fonte da organização no "Monorepositório". Para aqueles que não estão familiarizados com essa abordagem, a idéia é armazenar todo o código-fonte em um único repositório do sistema de controle de versão. Uma alternativa, é claro, é armazenar o código fonte em vários repositórios independentes, geralmente dividindo-os ao longo da borda de serviços / aplicativos / bibliotecas.
Neste post, chamarei essa abordagem de "poli-repositório".
Alguns dos gigantes de TI usam mono-repositórios, incluindo Google, Facebook, Twitter e outros. Obviamente, se essas empresas conceituadas usam mono-repositórios, os benefícios dessa abordagem devem ser enormes, e todos devemos fazer o mesmo, certo? Não! Como o título do artigo diz: “Por favor, não use o mono-repositório!” Porque Como,
em grande escala, o monorepositório resolverá todos os mesmos problemas que o poli-repositório, mas ao mesmo tempo, provocará a forte coerência do seu código e exigirá esforços incríveis para aumentar a escalabilidade do seu sistema de controle de versão .
Assim, a médio e longo prazo, o mono-repositório não oferece vantagens organizacionais, enquanto deixa os melhores engenheiros da empresa com síndrome pós-traumática (manifestada na forma de baba e murmúrios incoerentes sobre o desempenho do git).
Digressão curta: o que quero dizer com "em larga escala"? Não existe uma resposta única para essa pergunta, mas porque Tenho certeza que você me pergunta sobre isso, digamos que existem cerca de 100 desenvolvedores escrevendo código em tempo integral.
Vantagens teóricas de um monorepositório e por que elas não podem ser alcançadas sem ferramentas utilizadas para policreitoriais (ou falsas)
Vantagem teórica 1: Colaboração e compartilhamento de código mais fáceis
Os defensores dos mono-repositórios afirmam que, quando todo o código está no mesmo repositório, a probabilidade de duplicação de código é menor e é mais provável que equipes diferentes trabalhem juntas em uma infraestrutura comum.
Aqui está a verdade amarga sobre até mesmo os repositórios mono de tamanho médio (e isso soará constantemente nesta seção): rapidamente se torna impraticável para um desenvolvedor manter todo o código do repositório em sua estação de trabalho ou pesquisar toda a base de códigos usando utilitários como o grep. Portanto, qualquer mono-repositório que queira escalar deve fornecer duas coisas:
1) algo como um sistema de arquivos virtual que permite armazenar localmente apenas parte do código. Isso pode ser alcançado usando um sistema de arquivos proprietário como o
Perforce , que suporta esse modo nativamente, usando a ferramenta
G3 interna do Google ou o
GVFS da Microsoft.
2) ferramentas sofisticadas como serviço (como serviço) para indexar / pesquisar / visualizar o código-fonte. Porque Como nenhum dos desenvolvedores armazenará todo o código-fonte em sua estação de trabalho em um estado pesquisável, torna-se essencial poder realizar essa pesquisa em toda a base de código.
Com base no fato de que o desenvolvedor terá acesso a apenas uma pequena parte do código-fonte a qualquer momento, há pelo menos alguma diferença entre baixar uma parte do mono-repositório ou baixar vários repositórios independentes?
Não há diferença .
No contexto de indexação / pesquisa / navegação e código semelhante, uma ferramenta hipotética pode pesquisar facilmente vários repositórios e combinar o resultado. De fato, é exatamente assim que a pesquisa no GitHub funciona, bem como ferramentas de pesquisa e indexação mais sofisticadas, como o
Sourcegraph .
Portanto, do ponto de vista do trabalho colaborativo em código em larga escala, os desenvolvedores são obrigados a trabalhar apenas com parte da base de código e a usar ferramentas de nível superior. Não faz diferença se o código é armazenado em um repositório mono ou em vários repositórios independentes, o problema é resolvido da mesma maneira e a
eficácia de trabalhar juntos no código depende apenas da cultura de engenharia e não da maneira como os códigos-fonte são armazenados .
Vantagem teórica 2: gerenciamento de uma montagem / sem dependência
O próximo argumento, geralmente citado pelos defensores dos mono-repositórios, é que armazenar todo o código em um único mono-repositório priva você da necessidade de gerenciar dependências, como todo o código é coletado ao mesmo tempo. Isso é mentira! Em larga escala, simplesmente não há como reconstruir todo o código-fonte e executar todos os testes automatizados toda vez que alguém comete alterações no sistema de controle de versão (ou, mais importante, com mais frequência, no servidor de IC quando uma nova solicitação de ramificação ou pull é criada). Para resolver esse problema, todos os grandes repositórios mono usam seu sofisticado sistema de compilação (por exemplo,
Bazel / Blaze do Google ou
Buck do Facebook), projetado para monitorar alterações e seus blocos dependentes e criar um gráfico de dependência do código-fonte. Esse gráfico permite organizar o armazenamento em cache eficiente de resultados e testes de montagem, portanto, apenas as alterações e suas dependências precisam de remontagem e teste.
Além disso, desde o código coletado deve finalmente ser implantado e, como você sabe, nem todo software pode ser implantado de uma só vez, é importante que todos os artefatos de montagem sejam controlados, para que os artefatos sejam refeitos novamente, conforme necessário. Em essência, isso significa que, mesmo no mundo dos mono-repositórios, várias versões do código podem existir ao mesmo tempo na natureza e devem ser cuidadosamente monitoradas e coordenadas.
Os defensores dos mono-repositórios também argumentam que, mesmo levando em consideração a necessidade de rastrear assemblies / dependências, isso ainda oferece uma vantagem inegável, pois um único commit descreve o estado completo do mundo inteiro. Eu diria que essa vantagem é bastante controversa, já que o gráfico de dependência já existe, e parece uma tarefa bastante trivial incluir o identificador de confirmação para cada repositório independente como parte deste gráfico, e de fato o Bazel pode trabalhar facilmente com vários repositórios independentes, bem como um mono-repositório, abstraindo o nível subjacente do desenvolvedor. Além disso, é fácil implementar essas ferramentas de refatoração automatizadas que atualizam automaticamente as versões das bibliotecas dependentes em vários repositórios independentes de uma só vez, nivelando a diferença entre o monorepositório e o poli-repositório nesta parte (mais sobre isso posteriormente).
O resultado final é que as realidades da montagem / implantação em larga escala são as mesmas para os repositórios mono e poli-repositórios.
Não há diferença para ferramentas, não deve ser para desenvolvedores que escrevem código .
Vantagem teórica 3: a refatoração de código é um commit atômico simples
Finalmente, a última virtude mencionada pelos defensores dos mono-repositórios é o fato de um repositório simplificar a refatoração de código devido à facilidade de pesquisa e a idéia de que um único commit pode abranger todo o repositório. Isso não é verdade por vários motivos:
1) conforme descrito acima, em larga escala, o desenvolvedor não poderá editar ou pesquisar toda a base de códigos em sua máquina local. Portanto, a ideia de que alguém possa facilmente clonar todo o seu repositório para si mesmo e apenas fazer grep / replace não é tão fácil de colocar em prática.
2) mesmo se assumirmos que, com a ajuda de um sistema de arquivos virtual complexo, um desenvolvedor pode clonar e editar toda a base de código, com que frequência isso acontecerá? Não estou falando sobre corrigir um bug na implementação de uma biblioteca compartilhada, porque essa situação é tratada igualmente no caso de um único repositório e no caso de um multi-repositório (assumindo um sistema de compilação / implantação semelhante, conforme descrito acima). Estou falando de alterar a API da biblioteca, que será seguida por muitos erros de compilação nos locais onde essa biblioteca é chamada. Em uma base de código muito grande, é
quase impossível fazer uma alteração na API básica, que será visualizada por todas as equipes envolvidas antes que os conflitos de mesclagem forçam você a iniciar o processo novamente . O desenvolvedor tem duas possibilidades reais: ele pode desistir e encontrar uma solução alternativa para o problema com a API (na prática, isso acontece com mais frequência do que todos nós gostaríamos), ou ele pode desviar a API existente, escrever uma nova API e embarcar no longo e longo prazo. atualização dolorosa de todas as chamadas para a API antiga em toda a base de código. De qualquer forma,
esse é absolutamente o mesmo processo que o poli-repositório .
3) em um mundo orientado a serviços, os aplicativos consistem em muitos componentes fracamente acoplados que interagem entre si usando algum tipo de API bem descrita. Organizações maiores, mais cedo ou mais tarde, passarão a usar o IDL (linguagem de descrição da interface), como Thrift ou Protobuf, que permitem criar APIs de tipo seguro e fazer alterações compatíveis com versões anteriores. Conforme descrito na seção anterior sobre montagem / implantação, o
código não pode ser implantado simultaneamente . Ele pode ser implantado por um período de tempo: horas, dias ou até meses. Portanto, os desenvolvedores devem pensar na compatibilidade com versões anteriores de suas alterações. Essa é a realidade do desenvolvimento de software moderno, que muitos gostariam de ignorar, mas não podem. Portanto, quando se trata de serviços (ao contrário de bibliotecas de API), os desenvolvedores devem usar uma das duas abordagens descritas acima (não altere a API nem passe pelo ciclo de descontinuação) e
isso é absolutamente o mesmo para o monorepositório e o poli-repositório .
Por falar em refatoração de grandes bases de código, muitas grandes organizações estão desenvolvendo suas próprias ferramentas de refatoração automatizada, como o
fastmod , lançado recentemente pelo Facebook. Como sempre, essa ferramenta poderia trabalhar facilmente com um repositório ou vários independentes. O Lyft tem uma ferramenta chamada "refatorador" que faz exatamente isso. Funciona como o fastmod, mas automatiza as alterações em vários de nossos repositórios, incluindo a criação de solicitações pull, o status de rastreamento de revisões etc.
Desvantagens únicas dos monorepositórios
Na seção anterior, listei todas as vantagens teóricas que um monorepositório fornece e observei que, para tirar proveito delas, é necessário criar ferramentas incrivelmente complexas que não diferem das dos poli-repositórios. Nesta seção, mencionarei duas desvantagens exclusivas dos repositórios mono.
Desvantagem 1: Forte conectividade e software de código aberto
Organizacionalmente, um monorepositório provoca a criação de software frágil e fortemente acoplado. Isso dá aos desenvolvedores a sensação de que podem facilmente corrigir erros em abstrações, embora na realidade não possam devido ao processo instável de montagem / implantação e a fatores humanos / organizacionais / culturais que surgem ao tentar fazer alterações imediatamente em toda a base de código.
A estrutura do código nos poli-repositórios representa limites claros e transparentes entre equipes / projetos / abstrações / proprietários do código e força o desenvolvedor a considerar cuidadosamente a interface de interação. Essa é uma vantagem sutil, mas muito importante: faz com que os desenvolvedores pensem de maneira mais ampla e a longo prazo. Além disso, o uso de multi-repositórios não significa que os desenvolvedores não possam ir além dos limites do repositório. Se isso acontece ou não, depende apenas da cultura de desenvolvimento, e não se um monorepositório ou poli-repositório é usado.
A ligação forte também tem sérias conseqüências com relação à abertura do seu código fonte. Se uma empresa deseja criar ou consumir software de código aberto, o uso de multi-repositórios é obrigatório. As distorções que ocorrem quando uma empresa tenta apresentar seu projeto em código aberto a partir de seu mono-repositório (importação / exportação de códigos-fonte, rastreador de erros público / privado, camadas adicionais para abstrair a diferença nas bibliotecas padrão etc.) não levam a uma colaboração produtiva e construindo uma comunidade e criando uma sobrecarga significativa.
Falha 2: escalabilidade do sistema de controle de versão
Escalar um sistema de controle de versão para centenas de desenvolvedores, centenas de milhões de linhas de código e um enorme fluxo de confirmações é uma tarefa monumental. O mono-repositório do Twitter, criado há 5 anos (baseado no git), foi um dos projetos mais inúteis que eu já assisti na minha carreira. A execução de um comando simples como o
git status
levou
minutos . Se a cópia local do repositório era muito antiga, a atualização poderia levar
horas (naquela época, era até uma prática enviar discos rígidos com uma cópia do repositório para funcionários remotos com a versão mais recente do código). Lembro-me disso não para zombar dos desenvolvedores do Twitter, mas para ilustrar o quão complexo é esse problema. Posso dizer que cinco anos depois, o desempenho do repositório único do Twitter ainda está longe do que os desenvolvedores da equipe Tilling gostariam de ver, e isso não é porque eles se esforçaram bastante.
Obviamente, nos últimos 5 anos, houve algum desenvolvimento nessa área. O
Git VFS da Microsoft, usado para desenvolver o Windows, levou ao surgimento de um sistema de arquivos virtual real para o git, que descrevi acima como pré-requisito para dimensionar um sistema de controle de versão (e com a compra do Microsoft Github, parece que esse nível de dimensionamento encontrará seu aplicação nos recursos que o GiHub oferece a seus clientes corporativos). E, é claro, o Google e o Facebook continuam investindo enormes recursos em seus sistemas internos para que continuem funcionando, embora quase nada disso esteja disponível ao público.
Então, por que você geralmente precisa resolver esses problemas com o dimensionamento do sistema de controle de versão, se, conforme descrito na seção anterior, é necessário que o kit de ferramentas seja exatamente o mesmo do multirepositório? Não há razão razoável para isso.
Conclusão
Como geralmente acontece no desenvolvimento de software, olhamos para as empresas de software mais bem-sucedidas como exemplo e tentamos tomar emprestadas suas melhores práticas sem entender o que exatamente levou essas empresas ao sucesso. Monorepositórios, na minha opinião, são um exemplo típico de tal caso. Google, Facebook e Twitter investiram uma enorme quantidade de recursos em seus sistemas de armazenamento de código apenas para encontrar uma solução que é essencialmente a
mesma necessária para um repositório múltiplo, mas provoca forte ligação e requer um grande investimento no controle de versão em escala .
De fato, em larga escala, como uma empresa trabalha trabalhando em conjunto com código, colaboração, forte ligação etc.
depende diretamente da cultura e da liderança da engenharia e não tem a ver com o uso de um monorepositório ou polpositório . Ambas as soluções têm a mesma aparência para o desenvolvedor. Então, por que usar um monorepositório?
Por favor não!