Monorepositórios: por favor, é necessário.

Monorepositórios: por favor, é necessário.

A tradução do artigo foi preparada para os alunos do curso «Práticas e Ferramentas DevOps» no projeto educacional OTUS.

Você deve escolher um monorepositório, porque o comportamento que ele promove em suas equipes é a transparência e a responsabilidade coletiva, especialmente à medida que as equipes crescem. De qualquer forma, você terá que investir em ferramentas, mas sempre é melhor quando o comportamento padrão é aquele que você deseja ver em suas equipes.

Por que estamos falando sobre isso?

Matt Klein escreveu um artigo «Monorepos: Please don’t!»  (nota do tradutor: tradução no Habré «Monorepositórios: por favor, não»). Eu gosto do Matt, acho que ele é muito inteligente, e você deve ler seu ponto de vista. Inicialmente, ele publicou uma pesquisa no Twitter:

Monorepositórios: por favor, é necessário.

Tradução:
Neste dia de Ano Novo, vou discutir o quão absurdos são os monorepositórios. O ano de 2019 começou discretamente. No espírito disso, proponho a vocês uma pesquisa. Quem são os grandes fanáticos? Apoiante:
— Monorepositório
— Rust
— Pesquisa errada / ambos

Minha resposta foi: "Eu sou literalmente ambas as pessoas". Em vez de falar sobre como Rust é uma droga, vamos esclarecer por que eu acho que ele está errado sobre os monorepositórios. Um pouco sobre mim. Sou diretor técnico da Chef Software. Temos cerca de 100 engenheiros, uma base de código que tem aproximadamente 11–12 anos e 4 produtos principais. Parte desse código está em um polirepositório (minha posição inicial), parte em um monorepositório (minha posição atual).

Antes de começar: cada argumento que eu apresento aqui se aplicará a ambos os tipos de repositórios. Na minha opinião, não existem motivos técnicos para você escolher um tipo de repositório em detrimento do outro. Você conseguirá fazer qualquer abordagem funcionar. Estou feliz em discutir isso, mas não me interessam razões técnicas artificiais que alegam que um é superior ao outro.

Concordo com a primeira parte do ponto de vista do Matt:

Porque em grande escala, um monorepositório enfrentará os mesmos problemas que um polirepositório, mas ao mesmo tempo o levará a uma forte coesão de seu código e exigirá esforços incríveis para aumentar a escalabilidade do seu sistema de controle de versões.

Você terá que resolver os mesmos problemas, independentemente de escolher um monorepositório ou um polirepositório. Como você lança versões? Qual é a sua abordagem para atualizações? Compatibilidade reversa? Dependências cruzadas entre projetos? Quais estilos arquitetônicos são aceitáveis? Como você gerencia sua infraestrutura de construção e testes? A lista é interminável. E você irá resolver todos eles à medida que crescer. Não existe queijo grátis.

Acredito que o argumento do Matt reflete as opiniões compartilhadas por muitos engenheiros (e gerentes) que respeito. Isso vem da perspectiva de um engenheiro trabalhando em um componente, ou de uma equipe trabalhando em um componente. Você ouve coisas como:

  • A base de código é grosseira — não preciso de toda essa bagunça.
  • É mais difícil de testar, porque preciso checar toda essa bagunça que não preciso.
  • É mais complicado trabalhar com dependências externas.
  • Preciso de meus próprios sistemas virtuais de controle de versões.

Sem dúvida, todos esses pontos são válidos. Isso acontece em ambos os casos — no polirepositório eu tenho minha bagunça, além da que preciso para a construção... Eu posso precisar de mais bagunça. Por isso, eu 'simplesmente' crio ferramentas que fazem o checkout de todo o projeto. Ou crio um monorepositório falso com submódulos. Poderíamos discutir isso o dia todo. Mas acho que o argumento do Matt ignora a razão principal, que eu mudei bastante a favor do monorepositório:

Ele provoca comunicação e revela problemas.

Quando separamos repositórios, de fato criamos um problema de coordenação e transparência. Isso se alinha à forma como pensamos sobre equipes (especialmente à maneira como os indivíduos pensam sobre elas): somos responsáveis por um determinado componente. Trabalhamos em relativa isolação. As fronteiras estão fixadas em minha equipe e no(s) componente(s) em que trabalhamos.

Com a complexidade da arquitetura, uma equipe não pode mais gerenciá-la sozinha. Muito poucos engenheiros conseguem manter todo o sistema na cabeça. Suponha que você está gerenciando o componente A, que é utilizado pelas equipes B, C e D. A equipe A realiza refatoração, aprimora a API e altera a implementação interna. Como resultado, as mudanças não são compatíveis com versões anteriores. Que conselho você daria?

  • Encontre todos os lugares onde a API antiga está sendo utilizada.
  • Há lugares onde a nova API não pode ser utilizada?
  • Você pode corrigir e testar outros componentes para garantir que eles não quebrem?
  • Essas equipes podem verificar suas mudanças agora?

Note que essas questões não dependem do tipo de repositório. Você precisará localizar as equipes B, C e D. Você precisará conversar com elas, descobrir os prazos e entender suas prioridades. Pelo menos, esperamos que você faça isso.

Na verdade, ninguém quer lidar com isso. É muito menos emocionante do que simplesmente corrigir uma maldita API. É tudo muito humano e complicado. Em um repositório polido, você pode simplesmente fazer as alterações, enviar para revisão aqueles que trabalham nesse componente (provavelmente não B, C ou D) e seguir em frente. As equipes B, C e D podem ficar na versão atual por enquanto. Elas vão atualizar quando perceberem sua genialidade!

Em um monorepositório, a responsabilidade se desloca por padrão. A equipe A altera seu componente e, se não tomar cuidado, imediatamente quebra B, C e D. Isso faz com que B, C e D apareçam à porta de A, perplexos, perguntando por que a equipe A quebrou a construção. Isso ensina A que não pode ignorar minha lista acima. Elas devem conversar sobre o que planejam fazer. B, C e D podem avançar? E se B e C puderem, mas D estiver fortemente ligado ao efeito colateral do comportamento do algoritmo antigo?

Então, precisamos conversar sobre como vamos sair dessa situação:

  1. Suporte a múltiplas APIs internas, com o algoritmo antigo marcado como obsoleto, até que D consiga deixar de usar.
  2. Suporte a múltiplas versões de lançamentos, uma com a interface antiga e outra com a nova.
  3. Atrasar o lançamento das mudanças de A até que B, C e D possam aceitá-las simultaneamente.

Suponhamos que escolhemos 1, várias APIs. Neste caso, temos dois pedaços de código. Antigo e novo. Isso é bastante conveniente em algumas situações. Retornamos o código antigo, marcamos como obsoleto (deprecated) e alinhamos um cronograma para sua remoção com a equipe D. Essencialmente é idêntico para polí e para monorepositórios.

Para o lançamento de várias versões, precisamos de um branch. Agora temos dois componentes — A1 e A2. As equipes B e C usam A2, enquanto D usa A1. Precisamos que cada componente esteja pronto para o lançamento, pois, antes que D possa avançar, podem ser necessárias atualizações de segurança e correções de outros bugs. Em um polirepositório, podemos esconder isso em um branch de longa duração, que se sente bem. Em um monorepositório, forçamos a criação de código em um novo módulo. A equipe D ainda terá que fazer alterações no componente "antigo". Qualquer um pode ver o custo que estamos pagando aqui — agora temos o dobro de código, e quaisquer correções de bugs aplicadas a A1 e A2 devem ser aplicadas a ambos. Com a abordagem de usar branches em um polirepositório, isso está escondido sob cherry-pick. Consideramos o custo como menor porque não há duplicação. Do ponto de vista prático, o custo é o mesmo: você estará criando, lançando e mantendo duas bases de código, em sua maioria idênticas, até que possa remover uma delas. A diferença é que, no monorepositório, essa dor é direta e está à vista. É ainda pior, e isso é bom.

Finalmente, chegamos ao terceiro ponto. O atraso no lançamento. Pode ser que as mudanças feitas pela equipe A melhorem a vida da equipe A. Importante, mas não urgente. Podemos simplesmente atrasar? No monorepositório, estamos forçando isso para a consolidação do artefato. Claro, estamos falando sobre isso com a equipe D. Apenas continue na versão antiga até que você se atualize! Isso configura um jogo de covardes. A equipe A continua trabalhando em seu componente, ignorando o fato de que a equipe D está utilizando uma versão cada vez mais desatualizada (esse é um problema da equipe D, eles são tolos). Enquanto isso, a equipe D fala mal da atitude descuidada da equipe A em relação à estabilidade do código, se é que falam sobre isso. Meses se passam. Finalmente, a equipe D decide considerar a possibilidade de uma atualização, mas as mudanças na A só aumentaram. A equipe A mal se lembra de quando e como eles quebraram a D. A atualização é mais dolorosa e levará mais tempo. O que a envia mais para baixo na lista de prioridades. Até o dia em que temos um problema de segurança na A, que nos obriga a criar uma branch. A equipe A deve voltar no tempo, encontrar o momento em que a D estava estável, corrigir o problema lá e torná-lo pronto para o lançamento. Esta é uma escolha de fato que as pessoas fazem, e certamente é a pior. Parece ser bom tanto para a equipe A quanto para a D, enquanto pudermos ignorar uns aos outros.

No monorepositório, a terceira opção realmente não é viável. Você é forçado a lidar com a situação de uma das duas maneiras. Você precisa enxergar os custos de ter duas branches de lançamento. Aprender a se proteger contra atualizações que quebram a compatibilidade. Mas o principal: você não vai escapar de uma conversa difícil.

Na minha experiência, quando as equipes se tornam grandes, não há mais como manter todo o sistema na cabeça, e essa é a parte mais importante. Você deve melhorar a visibilidade das discrepâncias no sistema. Você deve trabalhar ativamente para fazer as equipes desviarem o olhar de seus componentes e olharem para o trabalho de outras equipes e consumidores.

Sim, você pode criar ferramentas que tentem resolver o problema dos polirrepositórios. Mas a minha experiência em entrega contínua e automação em grandes empresas me diz o seguinte: o comportamento padrão, sem o uso de ferramentas adicionais, é aquele que você espera ver. O comportamento padrão do polirrepositório é a isolação, esse é o foco. O comportamento padrão do monorrepositório é a responsabilidade compartilhada e a transparência, esse é o cerne. Em ambos os casos, vou criar uma ferramenta que ajude a suavizar as arestas. Como líder, escolherei o monorrepositório sempre, porque as ferramentas devem fortalecer a cultura que procuro, e a cultura vem de pequenas decisões e do trabalho diário da equipe.

Apenas usuários registrados podem participar da pesquisa. Entre, por favor.

Quem são os maiores fanáticos? Os defensores:

  • Monorepositório

  • Rust

  • Pesquisa errada / ambos

33 usuários votaram. 13 usuários se abstiveram.

Fonte: habr.com

Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS 🔥 Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS | ProHoster