Monorepo avec Rust : organisation du code pour les grands projets

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Introduction

À mesure qu'un projet Rust grandit, la question se pose : comment organiser le code pour qu'il reste maintenable, évolutif et pratique pour l'équipe ? Une approche populaire est le monorepository (monorepo). Dans cet article, nous allons décomposer ce qu'est un monorepository, comment l'organiser en utilisant Cargo workspace, et fournir des exemples pratiques. Vous apprendrez à structurer le code, gérer les dépendances et éviter les erreurs courantes.



Qu'est-ce qu'un monorepository et pourquoi est-il nécessaire en Rust ?

Un monorepository (ou monorepo) est un seul dépôt qui contient plusieurs projets (crates) ou paquets. Contrairement aux multi-dépôts, où chaque projet vit séparément, un monorepository combine tout : bibliothèques, binaires, tests, configurations et documentation.

Avantages d'un monorepository pour Rust :

  • Version de dépendance unique — tous les crates utilisent les mêmes versions des paquets externes, ce qui réduit les conflits.
  • Refactorisation simplifiée — les modifications dans une bibliothèque sont immédiatement visibles dans tous les crates dépendants.
  • Intégration de bout en bout — vous pouvez facilement exécuter des tests et du linting pour l'ensemble du projet.
  • Documentation centralisée — tous les documents et CI/CD sont au même endroit.

Cependant, un monorepository ne convient pas à tout le monde. Pour les petits projets ou les équipes avec des cycles de développement différents, il est préférable de choisir un multi-repo. Mais pour l'écosystème Rust, où la modularité et la réutilisation du code sont la norme, un monorepository devient un outil puissant.



Organisation d'un monorepository avec Cargo Workspace

Cargo prend en charge le mécanisme workspace — il s'agit d'un groupe de crates qui sont construits ensemble et partagent un Cargo.lock commun. Regardons la structure de base.



Création d'un workspace

Créez un répertoire racine et un fichier Cargo.toml sans section [package], mais avec une section [workspace] :

# root Cargo.toml[workspace]members = [    "core",    "cli",    "web",]

Créez maintenant les sous-répertoires core, cli, web. Chacun d'eux doit avoir son propre Cargo.toml avec une structure de paquet typique. Par exemple, pour core :

# core/Cargo.toml[package]name = "my_core"version = "0.1.0"edition = "2021"

[dependencies]serde = { version = "1.0", features = ["derive"] }

Pour cli et web, vous pouvez spécifier une dépendance sur my_core :

# cli/Cargo.toml[package]name = "my_cli"version = "0.1.0"edition = "2021"

[dependencies]my_core = { path = "../core" }clap = { version = "4.0", features = ["derive"] }

Maintenant, lorsque vous exécutez cargo build depuis la racine, tous les crates seront construits et Cargo.lock sera partagé.



Structure des dossiers et des modules

Structure de monorepository recommandée pour Rust :

my_monorepo/├── Cargo.toml          # workspace├── Cargo.lock├── core/               # bibliothèque avec types communs│   ├── Cargo.toml│   └── src/│       └── lib.rs├── cli/                # application console│   ├── Cargo.toml│   └── src/│       └── main.rs├── web/                # serveur web (par ex. sur Actix)│   ├── Cargo.toml│   └── src/│       └── main.rs├── tests/              # tests d'intégration (optionnel)│   └── integration_test.rs├── scripts/            # scripts pour CI/CD└── README.md

À l'intérieur de chaque crate, utilisez la structure de module Rust standard. Par exemple, dans core/src/lib.rs :

// core/src/lib.rspub mod models;pub mod utils;

Et dans core/src/models.rs :

// core/src/models.rsuse serde::{Serialize, Deserialize};

#[derive(Debug, Serialize, Deserialize)]pub struct

Blogs

Book Recommendations