Monorepository mit Rust: Code-Organisation für große Projekte

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Einführung

Mit dem Wachstum eines Rust-Projekts stellt sich die Frage: Wie organisiert man den Code, sodass er wartbar, skalierbar und teamfreundlich bleibt? Ein beliebter Ansatz ist das Monorepository (Monorepo). In diesem Artikel werden wir untersuchen, was ein Monorepository ist, wie man es mit Cargo workspace organisiert, und praktische Beispiele geben. Sie erfahren, wie Sie Code strukturieren, Abhängigkeiten verwalten und typische Fehler vermeiden.



Was ist ein Monorepository und warum wird es in Rust benötigt?

Ein Monorepository (oder Monorepo) ist ein einzelnes Repository, das mehrere Projekte (Crates) oder Pakete enthält. Im Gegensatz zu Multirepositories, bei denen jedes Projekt separat lebt, vereint ein Monorepository alles: Bibliotheken, Binärdateien, Tests, Konfigurationen und Dokumentation.

Vorteile eines Monorepositorys für Rust:

  • Einheitliche Version der Abhängigkeiten — alle Crates verwenden dieselben Versionen externer Pakete, was Konflikte reduziert.
  • Vereinfachtes Refactoring — Änderungen in einer Bibliothek sind sofort in allen abhängigen Crates sichtbar.
  • Durchgängige Integration — Tests und Linting können einfach für das gesamte Projekt ausgeführt werden.
  • Zentralisierte Dokumentation — alle Dokumente und CI/CD befinden sich an einem Ort.

Allerdings ist ein Monorepository nicht für jeden geeignet. Für kleine Projekte oder Teams mit unterschiedlichen Entwicklungszyklen ist ein Multirepo besser geeignet. Aber für das Rust-Ökosystem, wo Modularität und Code-Wiederverwendung die Norm sind, wird das Monorepository zu einem leistungsstarken Werkzeug.



Organisation eines Monorepositorys mit Cargo Workspace

Cargo unterstützt den Mechanismus workspace — eine Gruppe von Crates, die zusammen gebaut werden und eine gemeinsame Cargo.lock verwenden. Betrachten wir die grundlegende Struktur.



Erstellen eines Workspace

Erstellen Sie ein Stammverzeichnis und eine Datei Cargo.toml ohne den Abschnitt [package], sondern mit dem Abschnitt [workspace]:

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

Erstellen Sie nun die Unterverzeichnisse core, cli, web. In jedem davon muss eine eigene Cargo.toml mit der typischen Paketstruktur vorhanden sein. Zum Beispiel für core:

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

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

Für cli und web können Sie eine Abhängigkeit von my_core angeben:

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

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

Wenn Sie nun cargo build aus dem Stammverzeichnis ausführen, werden alle Crates gebaut, und die Cargo.lock ist gemeinsam.



Ordner- und Modulstruktur

Empfohlene Struktur eines Monorepositorys für Rust:

my_monorepo/├── Cargo.toml          # workspace├── Cargo.lock├── core/               # Bibliothek mit gemeinsamen Typen│   ├── Cargo.toml│   └── src/│       └── lib.rs├── cli/                # Konsolenanwendung│   ├── Cargo.toml│   └── src/│       └── main.rs├── web/                # Webserver (z.B. mit Actix)│   ├── Cargo.toml│   └── src/│       └── main.rs├── tests/              # Integrationstests (optional)│   └── integration_test.rs├── scripts/            # Skripte für CI/CD└── README.md

Verwenden Sie innerhalb jedes Crates die standardmäßige modulare Struktur von Rust. Zum Beispiel in core/src/lib.rs:

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

Und in core/src/models.rs:

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

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

Blogs

Buchempfehlungen