Monorepository mit Rust: Code-Organisation in der Praxis
\n\nBei der Entwicklung großer Projekte in Rust stellt sich früher oder später die Frage: Wie organisiert man den Code, damit er wartbar, wiederverwendbar und leicht skalierbar bleibt? Ein beliebter Ansatz ist das Monorepository. In diesem Artikel werden wir untersuchen, was ein Monorepository im Kontext von Rust ist, wie man es mit Cargo Workspaces einrichtet und welche praktischen Techniken helfen, Chaos in der Codebasis zu vermeiden.
Das Material wird sowohl für Anfänger nützlich sein, die gerade erst mit großen Projekten beginnen, als auch für erfahrene Entwickler, die nach effektiven Möglichkeiten zur Code-Organisation suchen.
\n\nWas ist ein Monorepository und warum wird es in Rust benötigt?
\n\nEin Monorepository (Monorepo) ist ein Ansatz, bei dem der gesamte Code eines Projekts (oder mehrerer verwandter Projekte) in einem einzigen Repository gespeichert wird. Im Gegensatz zu Multi-Repositories, bei denen jeder Dienst oder jede Bibliothek in einem eigenen Git-Repository lebt.
\n\nWarum entscheiden sich Rust-Entwickler oft für ein Monorepository?
\n- \n
- Einheitliche Abhängigkeitsversionen. Sie vermeiden Konflikte, wenn verschiedene Crates unterschiedliche Versionen derselben Bibliothek benötigen. \n
- Vereinfachtes Refactoring. Eine API-Änderung in einem Crate ist sofort in allen abhängigen Crates sichtbar – der Rust-Compiler zeigt alle Stellen an, die korrigiert werden müssen. \n
- Gemeinsame Kompilierung. Cargo kann den Build optimieren, indem es bereits kompilierte Artefakte wiederverwendet. \n
- Einheitliche Änderungshistorie. Sie müssen keine Commits zwischen verschiedenen Repositories synchronisieren. \n
Das wichtigste Werkzeug zur Organisation eines Monorepositorys in Rust sind Cargo Workspaces. Schauen wir uns an, wie man sie in der Praxis einsetzt.
\n\nEinrichtung von Cargo Workspaces: Schritt-für-Schritt-Beispiel
\n\nAngenommen, wir erstellen eine Anwendung, die aus drei Teilen besteht:
\n- \n
- Bibliothek
core_lib– gemeinsame Logik; \n - Bibliothek
utils– Hilfsprogramme; \n - ausführbare Datei
app– die Haupt-Binärdatei. \n
Erstellen wir die Struktur des Monorepositorys:
\n\nmy_monorepo/\n├── Cargo.toml # Root-Manifest des 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\nSchritt 1. Root-Cargo.toml
[workspace]\nmembers = [\n "core_lib",\n "utils",\n "app",\n]\n\n\nJetzt sind alle drei Crates Teil eines einzigen Workspace. Cargo wird sie als eine Einheit verwalten.
\n\nSchritt 2. Interne Abhängigkeiten
\nIn der Datei app/Cargo.toml geben wir an, dass sie von unseren Bibliotheken abhängt:
[package]\nname = "app"\nversion = "0.1.0"\nedition = "2021"\n\n[dependencies]\ncore_lib = { path = "../core_lib" }\nutils = { path = "../utils" }\n\n\nSchritt 3. Code schreiben
\nBeispielcode in core_lib/src/lib.rs:
pub fn greet(name: &str) -> String {\n format!("Hello, {}!", name)\n}\n\n\nIn app/src/main.rs verwenden wir diese Funktion:
use core_lib::greet;\n\nfn main() {\n println!("{}", greet("Rust Developer"));\n}\n\n\nSchritt 4. Build und Ausführung
\nDie Befehle cargo build, cargo test und cargo run funktionieren für den gesamten Workspace. Sie können auch einen bestimmten Crate ausführen:
cargo run -p app\ncargo test -p core_lib\n\n\nDies ist die grundlegende Einrichtung. Kommen wir nun zu fortgeschritteneren Praktiken.
\n\nFortgeschrittene Organisation: Module, Tests und Versionierung
\n\nWenn die Anzahl der Crates zunimmt, ist es wichtig, Disziplin zu wahren. Hier sind einige bewährte