Monorepositório com Rust: organização de código na prática

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Monorepositório com Rust: organização de código na prática

\n\n

Ao desenvolver projetos grandes em Rust, mais cedo ou mais tarde surge a pergunta: como organizar o código para que ele permaneça sustentável, reutilizável e facilmente escalável? Uma das abordagens populares é o monorepositório. Neste artigo, vamos explorar o que é um monorepositório no contexto do Rust, como configurá-lo usando Cargo Workspaces e quais técnicas práticas ajudam a evitar o caos na base de código.

\n\n

O material será útil tanto para iniciantes que estão começando a trabalhar com projetos grandes, quanto para desenvolvedores experientes em busca de maneiras eficientes de organizar o código.

\n\n

O que é um monorepositório e por que ele é necessário no Rust?

\n\n

Monorepositório (monorepo) é uma abordagem onde todo o código de um projeto (ou de vários projetos relacionados) é armazenado em um único repositório. Ao contrário dos multirrepositórios, onde cada serviço ou biblioteca vive em um repositório Git separado.

\n\n

Por que os desenvolvedores Rust frequentemente escolhem o monorepositório?

\n
    \n
  • Versão única de dependências. Você evita conflitos quando diferentes crates exigem versões diferentes da mesma biblioteca.
  • \n
  • Refatoração simplificada. A alteração de uma API em um crate é imediatamente visível em todos os crates dependentes — o compilador Rust apontará todos os lugares que precisam ser corrigidos.
  • \n
  • Compilação conjunta. O Cargo pode otimizar a construção, reutilizando artefatos já compilados.
  • \n
  • Histórico único de alterações. Você não precisa sincronizar commits entre diferentes repositórios.
  • \n
\n\n

A principal ferramenta para organizar um monorepositório em Rust é o Cargo Workspaces. Vamos ver como usá-lo na prática.

\n\n

Configuração do Cargo Workspaces: exemplo passo a passo

\n\n

Suponha que estamos criando uma aplicação composta por três partes:

\n
    \n
  • biblioteca core_lib — lógica comum;
  • \n
  • biblioteca utils — utilitários;
  • \n
  • arquivo executável app — binário principal.
  • \n
\n\n

Vamos criar a estrutura do monorepositório:

\n\n
my_monorepo/\n├── Cargo.toml          # manifesto raiz do workspace\n├── core_lib/\n│   ├── Cargo.toml\n│   └── src/\n│       └── lib.rs\n├── utils/\n│   ├── Cargo.toml\n│   └── src/\n│       └── lib.rs\n└── app/\n    ├── Cargo.toml\n    └── src/\n        └── main.rs\n
\n\n

Passo 1. Cargo.toml raiz

\n\n
[workspace]\nmembers = [\n    "core_lib",\n    "utils",\n    "app",\n]\n
\n\n

Agora todos os três crates fazem parte de um único workspace. O Cargo os gerenciará como um todo.

\n\n

Passo 2. Dependências internas

\n

No arquivo app/Cargo.toml, indicaremos que ele depende de nossas bibliotecas:

\n\n
[package]\nname = "app"\nversion = "0.1.0"\nedition = "2021"\n\n[dependencies]\ncore_lib = { path = "../core_lib" }\nutils = { path = "../utils" }\n
\n\n

Passo 3. Escrevendo o código

\n

Exemplo de código em core_lib/src/lib.rs:

\n\n
pub fn greet(name: &str) -> String {\n    format!("Hello, {}!", name)\n}\n
\n\n

Em app/src/main.rs, usamos esta função:

\n\n
use core_lib::greet;\n\nfn main() {\n    println!("{}", greet("Rust Developer"));\n}\n
\n\n

Passo 4. Compilação e execução

\n

Os comandos cargo build, cargo test e cargo run funcionam para todo o workspace. Também é possível executar um crate específico:

\n\n
cargo run -p app\ncargo test -p core_lib\n
\n\n

Esta é a configuração básica. Agora vamos para práticas mais avançadas.

\n\n

Organização avançada: módulos, testes e versionamento

\n\n

Quando o número de crates aumenta, é importante manter a disciplina. Aqui estão algumas dicas

Blogs

Book Recommendations