Monorepo com Bazel

Ronan Silva
Ship It!
Published in
4 min readApr 28, 2020
logo Bazel
https://bit.ly/3aFxrAg

TL;DR

Bazel é uma ferramenta open-source multiplataforma de automação de construção e testes de artefatos, similar ao Maven e Gradle. Suporta diversas linguagens de programação e repositórios imensos de código, por isso sua aderência à monorepo.

Você já precisou alterar uma dependência em diferentes pontos de diversos projetos? Depois da implementação, você sabia exatamente quais testes executar para garantir que estava tudo bem? Tendo passado por isso ou não, podemos supor que não seria uma tarefa corriqueira, mas e se fosse…

Definições

Antes de continuar, é importante esclarecer algumas estratégias de repositório de código e suas diferenças:

representação gráfica dos diferentes tipos de repositórios: monorepo, Single-repo e Multi-repo
https://bit.ly/2VJMFjz

Single-repo: Utilização de somente um repositório de código, com todo o código centralizado, normalmente com diversas responsabilidades, inclusive front e backend juntos, sem separação de projetos. Cenário comum quando se trata de monólitos.

Multi-repo: Utilização de diversos repositórios de código separados por projetos, com diversos projetos cada qual com sua responsabilidade sistêmica, um para backend e outro para frontend, por exemplo. Muito ligado à microsserviços, com cada projeto representando um serviço e em um repositório de código diferente.

Monorepo: Diversos projetos dentro de um mesmo repositório de código, devidamente organizados separadamente. Também associado à microsserviços, mas com somente um repositório. É aqui que vamos focar.

Bazel

Bazel é uma ferramenta open-source multiplataforma de automação de construção e testes de artefatos, similar ao Maven e Gradle. Suporta diversas linguagens de programação e repositórios imensos de código, por isso sua aderência à estratégia de monorepo.

Originalmente uma ferramenta interna do Google que tornou-se pública em 2015. De lá para cá evoluiu e encontra-se na versão 3.0. É utilizada por empresas como Google, Pinterest, Dropbox e r̶e̶c̶e̶n̶t̶e̶m̶e̶n̶t̶e̶ RD.

A ferramenta é capaz de armazenar uma cópia do estado dos arquivos e acompanhar alterações no conteúdo dos arquivos do projeto e nos arquivos de configuração (WORKSPACE e BUILD). Esses arquivos de configuração contém as dependências listadas. Dessa forma consegue detectar quando algo precisa ser reconstruído e reconstruir somente o que será afetado.

O fato de todo o código estar em um mesmo repositório e termos o mapeamento das dependências, permite que saibamos exatamente onde uma alteração causará impacto. Por exemplo:

  • Alterar a versão de uma biblioteca externa fará com que todos os projetos que dependam dela sejam reconstruídos e testados.
  • Alterar uma classe A disparará a reconstrução e teste de todas as classes que dependem de A, essas classes impactadas por sua vez vão disparar a reconstrução e teste de todas as classes que dependem delas e assim sucessivamente.

Vale ressaltar que todo teste tem seu resultado armazenado e não será executado se não for impactado por alguma alteração. Cenário propício para execuções concisas e rápidas em ferramentas de integração contínua (CI).

Exemplo

1 — Instalar bazel e maven (vamos usar Maven, através do Bazel, e seu repositório para baixar o jUnit).

2 — Clonar o projeto tutorial-bazel.

3 — Vamos trabalhar em um monorepo com 2 projetos, foo e bar, onde foo depende de bar. Ambos têm uma classe com o nome do projeto com um código e um teste com uma asserção simples.

.
├── bar
│ ├── BUILD
│ └── src
│ ├── main
│ │ └── java
│ │ └── Bar.java
│ └── test
│ └── java
│ └── BarTest.java
├── BUILD
├── foo
│ ├── BUILD
│ └── src
│ ├── main
│ │ └── java
│ │ └── Foo.java
│ └── test
│ └── java
│ └── FooTest.java
└── WORKSPACE

4 — Ao executar o comando bazel test //... teremos algo como:

//bar:BarTest PASSED in 0.8s
//foo:FooTest PASSED in 0.4s

5 — Ao repetir o comando, teremos uma resposta instantânea, devido ao cache dos testes.

//bar:BarTest (cached) PASSED in 0.8s
//foo:FooTest (cached) PASSED in 0.4s

6 — Vamos fazer uma pequena alteração na classe Foo.java, adicionar um linha por exemplo, e rodar os testes novamente.

//bar:BarTest (cached) PASSED in 0.8s
//foo:FooTest PASSED in 0.8s

(Somente foo será reconstruído, bar permanece igual ao cache)

7 — Hora de ver o comportamento no caso de alterações de dependências. Vamos fazer uma simples alteração na classe Bar.java, adicionar uma linha por exemplo, e executar os testes novamente.

//bar:BarTest PASSED in 0.5s
//foo:FooTest PASSED in 0.5s

(Como foo depende de bar, ambos serão reconstruídos)

8 — Ao executar novamente teremos uma resposta instantânea, devido ao cache dos testes:

//bar:BarTest (cached) PASSED in 0.5s
//foo:FooTest (cached) PASSED in 0.5s

Prós x Contras

Dentre alguns pontos favoráveis ao uso de monorepos, podemos citar:

  • Facilidade de gestão de repositório de código (padronização, formatação)
  • Facilidade de reuso e compartilhamento de código
  • Versionamento unificado, “one source of truth
  • Controle único de dependências
  • Maior colaboração entre diferentes times
  • Refatorações de larga escala (entre diversos serviços por exemplo)

Como nem tudo são flores, existem alguns pontos que exigem atenção, como:

  • Potencial aumento de complexidade de build/deploy
  • Gestão de dependências entre times pode ficar complexa (quem usa o quê)
  • Alterações indesejadas ou acidentais de código
  • Necessário preocupação/investimento em saúde do código

Conclusão

Estamos em um estágio inicial, testando e aplicando Bazel e a própria estratégia de monorepo aos poucos e em contexto específicos, como nossas pipelines de dados.

Como qualquer ferramenta, esta apresenta pontos favoráveis e contrários, portanto não devemos considerar a ferramenta ou a estratégia como balas de prata, mas ambas têm sido recursos muito úteis para grandes empresas, inclusive existe um caso de estudo no Google muito interessante que relata a experiência de desenvolvedores com monorepo.

Na dúvida se seria bom para seu time ou sua empresa? Teste e comente aqui!

Links

--

--