15 pontos por GN⁺ 2025-06-05 | 4 comentários | Compartilhar no WhatsApp
  • A adoção de um monorepo traz vantagens como consistência organizacional, compartilhamento de código e fortalecimento de um ambiente de ferramentas em comum, mas copiar diretamente os casos das big techs acaba levando a novos problemas e desafios
  • Para um monorepo bem-sucedido, é preciso seguir o princípio de fazer com que todas as tarefas principais sejam O(change), e não O(repo), exigindo ferramentas e estratégias adequadas em cada etapa de build, testes e CI/CD
  • Em controle de código-fonte, o ponto de partida é o Git, mas conforme a escala cresce é preciso considerar expansões graduais como sparse checkout e sistemas de arquivos virtuais
  • O sistema de build deve permanecer, sempre que possível, em uma única linguagem, sustentando-se o máximo possível nas ferramentas nativas de build de cada linguagem e migrando gradualmente para Bazel/Buck2 apenas quando realmente necessário
  • Em testes e CI/CD, é necessário detectar rapidamente apenas o escopo impactado pelas mudanças para buildar, testar e implantar, e em monorepos de grande porte também são indispensáveis estratégias de confiabilidade como retry automático de testes e isolamento de flaky tests

Introdução: o início da jornada rumo ao monorepo

  • Para engenheiros em uma nova equipe de Developer Productivity, a preocupação cresce em torno de quais preparações e esforços são necessários depois da decisão de adotar um monorepo
  • As boas práticas de grandes empresas como Google, Meta e Uber parecem impressionantes, mas na prática é impossível obter o mesmo nível de resultado que elas
  • Cada organização deve decidir pela adoção de um monorepo com base em suas próprias razões e necessidades, e nesse processo pode buscar vantagens em consistência, integração organizacional e ferramentas compartilhadas

Tornando clara a necessidade de um monorepo

  • Os casos de grandes empresas são apenas o estado a que elas chegaram no fim, e não servem bem como referência para o começo
  • Na prática, surgem novos problemas, e aparecem tipos de questões diferentes das de um sistema tradicional de vários repositórios
  • O objetivo de adotar um monorepo está em manter consistência, integrar ferramentas em toda a organização e aplicar padrões e convenções de engenharia
  • Cada equipe precisa deixar claros os objetivos alinhados à sua própria cultura e direção para obter resultados eficazes

Regra de ouro: o princípio de O(change)

  • Todas as ferramentas relacionadas ao repositório devem ter complexidade O(change), e não O(repo), para funcionarem rapidamente
  • Na prática, quanto maior o monorepo em larga escala, mais evidentes ficam as ineficiências das ferramentas existentes, tornando essencial um desenho estrutural para superar os problemas de desempenho
  • As inovações mencionadas nos blogs técnicos das grandes empresas também se concentram, em sua maioria, em superar as ineficiências causadas por O(repo)

Controle de código-fonte

  • A maioria das organizações de software usa Git como base, mas o Git tem limites de desempenho quando precisa escalar em um ambiente de monorepo centralizado
    • Na prática, a maioria das organizações consegue ir bastante longe usando git+GitHub
  • À medida que o crescimento acelera, passam a ser necessárias estruturas como sparse checkout (clone parcial) e sistemas de arquivos virtuais (download dinâmico de arquivos do servidor quando necessário)
  • Grandes empresas fazem fork do Git ou desenvolvem sistemas separados para isso (Microsoft: fork próprio do Git, Meta: fork do Mercurial, Google: Piper etc.)
    • Também vale considerar controles de código-fonte de nova geração, como Jujutsu
  • Em escala pequena, é possível usar Git sem grandes dificuldades, mas é importante manter uma estratégia de expansão em mente ao longo do crescimento
  • Há também o problema prático de que, quando o código-fonte inclui código gerado por IDL (Interface Definition Language), o tamanho do repositório pode crescer exponencialmente

Sistema de build

  • Bazel e Buck2 são ferramentas representativas de build para monorepo, com suporte a várias linguagens e grafos de build complexos
    • São poderosas, mas trazem grande complexidade e custo operacional
  • Manter o build em uma única linguagem torna tudo muito mais simples, e os sistemas de build de cada linguagem (por exemplo: Maven, Gradle, Cargo, Go) também têm alta escalabilidade
  • O papel central do sistema de build é “buildar de forma eficiente o target especificado (geração eficiente de artefatos)” e “determinar rapidamente os targets afetados por arquivos alterados”
  • Para isso, é necessário o conceito de target determinator (ferramenta de determinação de targets), e já existem várias soluções nos ecossistemas de Rust, Go, Bazel etc.
  • Execução remota e cache só se tornam realmente necessários em escala extremamente grande; para empresas comuns, a determinação de targets é mais prática

Testes

  • Como executar todos os testes a cada vez é ineficiente, é necessário um sistema que teste apenas o escopo impactado pelas mudanças
  • Flaky tests podem se tornar um problema ainda mais sério em sistemas de teste de grande escala
  • O sistema de testes precisa de retry automático, avaliação automática do escopo impactado e isolamento de flaky tests
  • Algumas linguagens (por exemplo, Rust com nextest, Java com JUnit etc.) oferecem esses recursos avançados por padrão ou por extensão
  • A estrutura de testes de um monorepo precisa estar fortemente integrada ao sistema de build para ser eficaz

Integração contínua (CI)

  • O sistema de CI deve executar automaticamente os artefatos de build e as validações necessárias de acordo com as mudanças
  • O desempenho e a eficiência do target determinator funcionam como elementos centrais do pipeline de CI
  • O CI moderno usa várias estratégias, como Merge Queue, para equilibrar manutenção da qualidade do código e otimização da velocidade de merge
    • Por exemplo, decidir se toda validação será executada a cada commit/PR individual, se apenas parte dela será selecionada, ou se vários PRs serão processados em lote
  • É preciso definir e projetar internamente os trade-offs entre throughput, correctness e tail latency
  • O gerenciamento de merges e o aumento de eficiência de CI em monorepos muito grandes ainda são desafios sem solução perfeita
  • Rust (bors), Chromium e Uber adotam, cada um, estratégias diferentes de merge/validação

Entrega contínua (CD)

  • A ilusão de que toda mudança dentro do monorepo será implantada atomicamente não corresponde à realidade
  • Em um único PR, é possível alterar de uma vez interfaces, implementações e até clientes de vários serviços, mas no fim a implantação real ocorre de forma assíncrona, o que pode gerar problemas no momento do deploy
  • Mudanças que quebram contratos entre serviços podem causar falhas graves no momento da implantação
  • Uma estratégia eficaz de CD para monorepo exige o ciclo do sistema de deploy, validação de contratos entre serviços e capacidade de detectar e responder rapidamente a problemas

Conclusão

  • O monorepo é uma ferramenta poderosa para fortalecer a consistência organizacional e a cultura de engenharia, mas exige investimento contínuo em engenharia e ferramentas
  • Em cada etapa, o ponto central é construir automação, ferramentas e cultura alinhadas ao princípio de O(change)
  • À medida que a organização cresce, as ferramentas também devem evoluir continuamente, e é importante um esforço sistemático de gestão que reflita os objetivos e a cultura da organização
  • Com preparo, comprometimento e investimento contínuo suficientes, o monorepo acaba entregando um valor compatível com esse esforço

4 comentários

 
bichi 2025-06-05

É um texto realmente substancioso. Não basta ter ferramentas poderosas; é preciso estar preparado para criar até mesmo as ferramentas necessárias quando for preciso. Por isso, se tudo funcionar bem, os benefícios que se obtêm também são muitos.

 
cosine20 2025-06-05

Na época do mestrado, meu orientador foi almoçar com um engenheiro que tinha vindo do Google, ouviu falar sobre monorepo e voltou propondo que nós também passássemos a gerenciar tudo assim no futuro; foi um sufoco tentar dissuadi-lo...
Monorepo realmente tem muitas vantagens, mas no nosso laboratório, pela própria natureza do trabalho, era frequente precisarmos compartilhar os resultados com pessoas de fora, e acho que teríamos sofrido bastante justamente nessa parte se tivéssemos gerenciado esses resultados em um monorepo. Com multirepo, basta ajustar o nível de visibilidade de cada entrega separadamente.

 
youngrok 2025-06-05

A maioria dos casos em que se sofre com monorepo parece acontecer quando o projeto já foi fragmentado demais. Pegam um projeto que originalmente poderia ser um ou dois e dividem em uns 10; depois, ao tentar unificar e gerenciar tudo isso em um monorepo, acabam precisando usar também ferramentas de gestão de monorepo, e a complexidade aumenta. O melhor é integrar o próprio projeto em um ou dois, e mesmo que sejam mais de dois, em vez de usar uma ferramenta de gerenciamento separada, dá para pensar de forma mais simples: apenas dividir por diretórios e colocar tudo em um único repositório, o que torna a manutenção bem mais tranquila.

 
GN⁺ 2025-06-05
Comentários do Hacker News
  • Pedido de compartilhamento de experiências: esta thread fez lembrar as antigas conversas sobre os complexity merchants. Não concordo nem um pouco com a opinião de que migrar para um monorepo exige sacrifícios técnicos. Se você entende o poder de um sistema de arquivos hierárquico, entende o valor de um monorepo. CI/CD também fica muito mais claro quando organizado em um único monorepo, em vez de configurações espalhadas por todo lado. O ponto central do monorepo é que toda a organização pode fazer commits atômicos. Ao coordenar muitos desenvolvedores, a utilidade disso é esmagadora. Um único rebase e uma grande reunião bastam. Mesmo que os membros do time não se gostem nem colaborem entre si, do ponto de vista de gestão o monorepo funciona como uma grande ferramenta de RH.

    • Ultimamente os desenvolvedores têm uma tendência excessiva à separação, microservices, muitos repositórios pequenos e uma aversão extrema a monólitos. Isso aumenta a complexidade e transforma problemas de estrutura organizacional em problemas técnicos futuros. Também há uma incapacidade de reconhecer corretamente as dependências internas dos sistemas de software. No emprego anterior, o tempo desperdiçado para atualizar arquivos de esquema do Protocol Buffers era inacreditável. Felizmente, na empresa atual não é assim.

    • Rastrear commits em vários projetos é algo apenas desejável, e na prática não faz tanta diferença em termos de rastreamento de dependências ou disparo de testes downstream. Automação em multirepo também consegue resolver isso bem. O monorepo ajuda, mas não é completo e o custo é alto. Deploy e build não são processados atomicamente. Quando o monorepo cresce, é preciso sair do git e adotar novas ferramentas, e isso é um trabalho enorme. Não é algo sobre o qual se fala com facilidade sem experiência real.

    • As vantagens do monorepo certamente existem, mas o custo de gestão é mais alto do que no polyrepo. Monorepo não é automaticamente melhor em qualquer situação. Para uma explicação mais detalhada, veja este texto. A relação custo-benefício depende do contexto.

    • Uma regra prática útil no desenho de ambientes de programação é: quanto mais poder se dá ao time, mais problemas aparecem. Tecnicamente, commits atômicos não são um poder maior, mas sim menor; ainda assim, por possibilitarem trabalhar com interfaces ruins, acabam sendo um tipo de poder que gera problemas.

    • A crença de que, ao mudar para um monorepo, as mudanças se tornam mais atômicas é uma armadilha. [Citação do original: a maior ilusão do monorepo é achar que commits atômicos no codebase inteiro são possíveis. Na prática, existem vários artefatos de deploy; mesmo que serviços e clientes sejam alterados ao mesmo tempo, o deploy acontece de forma assíncrona. Em vários repositórios, é preciso trabalhar com vários PRs, então a percepção de risco já vem embutida. O CI do monorepo serve principalmente para validar contratos de serviço (jobs de CI) e, quando necessário, exige explicitar o motivo da mudança.]

  • Existem dois tipos de monorepo em big tech. O primeiro é o único monorepo corporativo, o "THE" monorepo citado no texto, que exige VCS/CI customizados e tem suporte de 200 engenheiros. Google, Meta e Uber seguem esse modelo. O sofrimento para chegar a esse nível vai muito além do imaginável, e normalmente começa com monorepos menores, por time, que vão se expandindo aos poucos. Cada stack/linguagem/time se gerencia com ferramentas como Bazel, Turborepo e Poetry, e com o tempo tudo acaba se juntando em um monorepo maior. Mas, em ambos os casos, tanto desenvolvedores quanto o negócio investem milhões de dólares e milhões de horas, e no fim tudo se sustenta com o apoio dos desenvolvedores que sobreviveram ao processo.

    • Quando trabalhei numa empresa com um monorepo grande, passei a preferir muito mais monorepo. Um monorepo único ajuda muito a enxergar com transparência o todo — o grafo de serviços, a estrutura de chamadas de código etc. No polyrepo, o conhecimento fica disperso por times, é difícil assumir código novo, e entender os arquivos de código parece explorar um labirinto. O polyrepo dá a sensação de mensagens antigas de Discord/Slack que acabam esquecidas. Se o monorepo é caro, o polyrepo também é, só que de outra forma. O monorepo é como um gigantesco herbívoro continental; o polyrepo é uma diversidade de espécies soterradas na escuridão.

    • Na empresa atual, o backend está dividido em cerca de 11 repositórios git, e para uma única funcionalidade são necessários 4 ou 5 merge requests, o que é muito incômodo. Estamos avaliando adotar monorepo para reunir vários projetos. Mas, se não for possível juntar os repositórios, qual seria a alternativa ao monorepo?

    • Ainda não existe um sistema de orquestração de monorepo fácil e poderoso, independente de linguagem. Bazel é complexo e difícil de aprender, embora a documentação tenha melhorado bastante ultimamente. Há outras opções como Buck, NX e Pants, mas cada uma tem suas características, e o suporte a web em especial é limitado. A maioria dos CIs não dá suporte adequado a essas ferramentas, então a configuração é trabalhosa. Como referência, o Rush da Microsoft oferece a melhor experiência; especialmente para monorepos de frontend/NodeJS, a recomendação é o site oficial do Rush.

    • Vale lembrar que a maioria dos monorepos não cresce até o porte de Google, Uber ou Meta. O número de serviços varia conforme a empresa e, mesmo que chegue a 100, isso ainda não gera problema de escala no VCS, e até tags de LSP rodam tranquilamente em um laptop. Mesmo rodar todos os testes indiscriminadamente no CI costuma ser aceitável. Conclusão: nem toda empresa precisa de escala de Google.

    • Na empresa atual, estamos montando monorepos por stack de linguagem. É um meio-termo bastante razoável.

  • Um ponto que quase nunca aparece na discussão monorepo vs multirepo é o surgimento da “lei de Conway reversa”. A estrutura dos repositórios influencia a estrutura organizacional e a forma de resolver problemas. Monorepo tende a gerar trabalho heroico para times de infraestrutura compartilhada; como há mais potencial de quebra ao mexer em áreas comuns, até desenvolver uma única funcionalidade fica mais difícil. No multirepo, são necessários vários PRs, coordenação entre times e política interna, mas uma variedade maior de desenvolvedores consegue distribuir esses papéis.

    • Mesmo em monorepo, se a mudança estiver profundamente conectada à parte central, ela pode ser aplicada em várias etapas. Nesse processo, também é preciso lidar com vários PRs, coordenação e questões políticas, mas justamente por ser monorepo fica mais claro visualizar a situação do rollout.

    • Em polyrepo, é muito mais comum que mudanças em áreas compartilhadas não sejam propagadas para repositórios downstream, de modo que cada repositório fica preso a uma versão diferente e passa anos sem atualização, causando sofrimento.

    • Fica a pergunta se faz sentido assumir que a organização escolhe primeiro a direção via estrutura de repositório e só depois as escolhas técnicas acompanham. Na prática, antes da estrutura concreta dos repositórios vem uma filosofia organizacional mais fundamental (fragmentação vs compartilhamento). Mesmo que a direção mude, a forma de gerenciar o código pode ser ajustada. Mesmo em multirepo, os engenheiros podem ter acesso a quase todo o código; e em monorepo também é possível aplicar isolamento forte, além de regras separadas de CI ou deploy.

    • Em monorepo, mudanças fáceis entre projetos acontecem com muito mais frequência; no polyrepo, muitas vezes isso é tão incômodo que nem se tenta.

  • Pela experiência em grandes empresas de tecnologia, a gestão do sistema de build exige um time dedicado. Monorepos grandes se baseiam em sistemas de arquivos virtuais que baixam os arquivos-fonte quando necessário. Um ponto não mencionado no artigo é que quase todo o desenvolvimento acontece em servidores de desenvolvimento no datacenter, usando ambientes com 50 a 100 cores ou containers sob demanda (atualizados continuamente para o commit mais recente). A IDE se integra ao dev server, e a preparação/configuração automática por linguagem ou serviço é automatizada com chef/ansible. É muito raro desenvolver diretamente um monorepo enorme no laptop (exceções: mobile, apps para Mac etc.).

    • Provavelmente alguém que trabalhou no mesmo time de build. Seja local ou remoto, em um ambiente de desenvolvimento para monorepo a reprodutibilidade é mais importante. Se o dev server remoto é baseado em imagens, fica ainda mais fácil e confiável.

    • Também há experiência usando ambiente de desenvolvimento em datacenter em times menores. Com os preços e a densidade do hardware hoje, faz muito mais sentido montar um rack próprio e rodar sob demanda ferramentas de dev/staging/test. Quando se compartilha um ambiente de desenvolvimento semelhante ao de produção, o modelo de monorepo parece bem diferente. Mas empresas pequenas e médias não têm fôlego para investir em sistema de build, e nesses casos o próprio problema de grandes sistemas de build nem chega a surgir (em equipes de no mínimo 10 a 20 pessoas, mesmo com um produto muito complexo, a manutenção pode continuar sendo só part-time).

  • Relato de uma equipe pequena no Molnett (serverless cloud), com 1,5 pessoa em tempo integral, que obteve enorme eficiência com um monorepo baseado em Bazel. Com Tilt+Bazel+Kind, conseguem subir no laptop a plataforma inteira e até o operador de Kubernetes, com suporte a Mac/Linux. Também conseguem validar localmente até o OS baseado em Bottlerocket e o Firecracker. Com a construção de uma camada de ferramentas, todos os desenvolvedores usam as mesmas versões de go/kubectl, sem instalação local. Dá trabalho manter, mas foi possível graças a um ex-membro do Google SRE. Querem continuar trabalhando assim. (As principais linguagens são Golang, Bash e Rust)

    • Com uma equipe minúscula de 1,5 pessoa, um repositório único é o natural. A experiência com Bazel foi péssima, mas talvez valha a pena em projetos grandes. Em equipes com menos de 2 pessoas, Kind+Tilt por si só já basta. A camada de ferramentas também é algo que Go já resolve em parte com go.mod. O mesmo pode ser feito de forma parecida com kubectl. Também vale pensar no nível salarial de um ex-Googler. Espero que o custo de manutenção do Bazel continue valendo a pena.

    • Na nossa empresa, fazemos deploy com serviços baseados em systemd e playbooks do ansible, e com tmuxinator inicializamos automaticamente em modo dev, de uma vez, backend/DB/motor de busca/frontend. Basta rodar o comando tmuxinator na raiz e todo o ambiente de desenvolvimento sobe na hora. Um monorepo único é esmagadoramente mais conveniente do que antes.

    • Situação parecida aqui, com relato de enorme efeito positivo ao introduzir Bazel. Graças à camada de ferramentas, o ambiente de desenvolvimento se mantém consistente. No entanto, é preciso usar bazel run manualmente, e ficou a curiosidade sobre formas melhores de automação. Pedido para explicar como isso funciona.

    • Em uma equipe de 2 pessoas, o próprio padrão de microservices/K8s já é overengineering. Nessa escala, qualquer abordagem funciona. Antigamente tudo rodava com Dropbox/SVN/MS VCS etc. (havia inconvenientes, claro), mas nada disso era realmente um problema. Nessa escala, todos conseguem manter o processo inteiro na cabeça. O relato é que ferramentas e infraestrutura complexas não são o fator de sucesso.

  • Relato de um freelancer que configurou monorepos três vezes em várias empresas ao longo dos últimos 4 anos. Como ficou restrito ao frontend e só usou o ecossistema JavaScript/TypeScript, isso tornou a gestão relativamente mais fácil. Um bom monorepo, na prática, funciona internamente como um polyrepo: cada projeto pode ser desenvolvido, implantado e hospedado de forma independente, mas coexistindo em uma única base de código, com compartilhamento livre de componentes comuns (UI etc.) e garantia de consistência visual. Como guia prático, recomenda este material.

    • Na verdade, isso não é polyrepo, e sim um caso de monorepo bem construído.
  • No fim das contas, tudo depende do caso. Na nossa empresa, gerenciamos cerca de 40 repositórios git com CIs separados; depois de build/test/package, no final geramos uma imagem integrada de sistema de arquivos para testes de integração. Os componentes se comunicam por mensagens Flatbuffers, e o próprio flatbuffers também é gerenciado como submodule. Lidar com dependências downstream é difícil, mas alguma flexibilidade foi garantida com progressive enhancement. Numa situação assim, nem fica claro se isso é multirepo ou um monorepo cheio de submodules. Também não é evidente se haveria vantagens em mudar para monorepo. No fim, trata-se de trade-offs e de escolher que tipo de inconveniência você está disposto a tolerar.

  • Relato do autor do blog sobre ferramentas para monorepo. As pessoas costumam destacar só as vantagens do monorepo, mas na prática a complexidade de operar um monorepo com sucesso quase sempre é absorvida nos bastidores por times de devops/devtools. Por isso, a adoção deve ser cautelosa, embora, quando bem implementado, possa oferecer valor suficiente.

  • A experiência com um monorepo bem administrado é tão boa que dá vontade de nunca mais voltar para outro workflow. Mas a abordagem despreparada de “vamos de monorepo também” é um pesadelo. Se alguém vendesse um pacote com ambiente e ferramentas de monorepo já prontos, haveria uma grande oportunidade de negócio.

    • A NX já faz esse negócio. Na startup anterior, começamos do zero com NX e, com um time de P&D de 15 pessoas, alcançamos uma padronização de nível de empresa com 100 pessoas. Já na empresa nova (que adquiriu a startup), a tentativa sem planejamento de “vamos de monorepo também” virou desastre. Agora estamos migrando para NX e o efeito está sendo muito bom.
  • Pela experiência em grandes organizações, monorepo pode até restringir drasticamente as dependências entre times e reduzir o reuso de código. Quando um time de bibliotecas quer mudar algo, todos os usuários abaixo precisam ser atualizados, e isso se complica porque outros times usam de formas inesperadas (Hyrum's Law). No fim, grandes empresas acabam caindo em copiar e colar internamente, forks, controle de acesso rígido e aprovação lenta de mudanças.

    • Ao criar uma biblioteca para uso geral, é preciso ter muito cuidado no design da API. Se possível, o ideal é não mudar a API; se for preciso mudar, recomenda-se planejar bem a mudança em larga escala ou substituir por uma nova função e marcar a versão antiga como deprecated. Para código pequeno, copiar e colar também pode ser aceitável.

    • Ainda assim, a vantagem do monorepo é conseguir encontrar facilmente todos os usos e, quando necessário, alterá-los/corrigi-los de forma atômica.

    • Todo software precisa considerar dependências, e o monorepo, pelo contrário, aumenta o poder tanto de quem mantém a biblioteca quanto de quem a utiliza para modificar um ao outro.

    • Em monorepo, como é fácil adaptar o código à própria necessidade, a chance de reutilização é maior do que em polyrepo.