Monorepositório com Java: como organizar o código de um grande projeto
No desenvolvimento moderno de projetos Java, surge frequentemente a questão: armazenar todos os componentes em um único repositório (monorepositório) ou dividi-los em vários repositórios separados (multirrepositório)? Monorepositório (monorepo) é uma abordagem onde o código de vários projetos, bibliotecas e serviços é armazenado em um único sistema de controle de versão. Neste artigo, vamos analisar como organizar eficientemente o código Java em um monorepositório, usando Maven e Gradle, e examinar exemplos práticos.
Vantagens e desvantagens do monorepositório para Java
Antes de passar à implementação, é importante entender quando o monorepositório é justificado. Para projetos Java, ele é especialmente útil se você possui bibliotecas compartilhadas, modelos de dados ou interfaces usados por vários serviços.
Prós do monorepositório
- Versão única de dependências: todos os módulos usam as mesmas versões de bibliotecas, o que elimina conflitos.
- Refatoração simples: a alteração de uma API comum ou modelo de dados ocorre atomicamente em um único commit.
- CI/CD simplificado: um único pipeline para compilar e testar todos os módulos.
- Transparência: cada desenvolvedor vê todo o código do projeto, o que facilita a compreensão da arquitetura.
Contras e como mitigá-los
- Tamanho do repositório: com o tempo, pode se tornar enorme. Solução: usar
.gitignoree não armazenar artefatos binários. - Complexidade da configuração de CI: é necessário saber executar apenas os módulos alterados. Ferramentas como Bazel ou Gradle Build Cache ajudam.
- Revisão de código demorada: se todas as alterações passam por um único pull request. Solução: usar branch policies e gatilhos automáticos.
Estrutura do monorepositório com Java: exemplo prático
Vamos considerar uma estrutura típica para um monorepositório Java usando Maven. Suponha que temos três módulos: core (lógica comum), service-api (REST API) e service-worker (processador em segundo plano).
my-java-monorepo/├── pom.xml # POM pai├── core/│ ├── pom.xml│ └── src/│ └── main/java/com/example/core/│ └── Utils.java├── service-api/│ ├── pom.xml│ └── src/│ └── main/java/com/example/api/│ └── MainController.java├── service-worker/│ ├── pom.xml│ └── src/│ └── main/java/com/example/worker/│ └── WorkerTask.java└── .gitignorePOM pai (pom.xml)
Na raiz do projeto, é criado um POM pai que gerencia as versões e lista os módulos:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>my-java-monorepo</artifactId> <version>1.0.0</version> <packaging>pom</packaging>
<modules> <module>core</module> <module>service-api</module> <module>service-worker</module> </modules>
<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>3.2.0</version> <type>pom</type> <scope>import</scope>