مستودع أحادي مع Rust: تنظيم الكود عمليًا

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

مستودع أحادي مع Rust: تنظيم الكود عمليًا

\n\n

عند تطوير مشاريع كبيرة بلغة Rust، يطرح السؤال عاجلاً أم آجلاً: كيف ننظم الكود بحيث يبقى قابلاً للصيانة وإعادة الاستخدام وقابلًا للتوسع بسهولة؟ أحد الأساليب الشائعة هو المستودع الأحادي (monorepo). في هذه المقالة، سنشرح ما هو المستودع الأحادي في سياق Rust، وكيفية إعداده باستخدام Cargo Workspaces وما هي الأساليب العملية التي ستساعد في تجنب الفوضى في قاعدة الكود.

\n\n

ستكون المادة مفيدة لكل من المبتدئين الذين بدأوا للتو العمل مع المشاريع الكبيرة، والمطورين ذوي الخبرة الذين يبحثون عن طرق فعالة لتنظيم الكود.

\n\n

ما هو المستودع الأحادي ولماذا هو مطلوب في Rust؟

\n\n

المستودع الأحادي (monorepo) هو نهج يتم فيه تخزين جميع كود المشروع (أو عدة مشاريع مرتبطة) في مستودع واحد. على عكس المستودعات المتعددة (multirepos)، حيث يعيش كل خدمة أو مكتبة في مستودع Git منفصل.

\n\n

لماذا يختار مطورو Rust غالبًا المستودع الأحادي؟

\n
    \n
  • إصدار موحد للتبعيات. تتجنب التعارضات عندما تتطلب صناديق (crates) مختلفة إصدارات مختلفة من نفس المكتبة.
  • \n
  • إعادة هيكلة مبسطة. تغيير API في صندوق واحد يظهر فورًا في جميع الصناديق التابعة له — سيشير مترجم Rust إلى جميع الأماكن التي تحتاج إلى تعديل.
  • \n
  • الترجمة المشتركة. يمكن لـ Cargo تحسين عملية البناء عن طريق إعادة استخدام القطع المترجمة بالفعل.
  • \n
  • تاريخ تغييرات موحد. لست بحاجة إلى مزامنة الالتزامات (commits) بين مستودعات مختلفة.
  • \n
\n\n

الأداة الرئيسية لتنظيم المستودع الأحادي في Rust هي Cargo Workspaces. دعنا نرى كيفية استخدامها عمليًا.

\n\n

إعداد Cargo Workspaces: مثال خطوة بخطوة

\n\n

لنفترض أننا ننشئ تطبيقًا يتكون من ثلاثة أجزاء:

\n
    \n
  • مكتبة core_lib — المنطق العام؛
  • \n
  • مكتبة utils — الأدوات المساعدة؛
  • \n
  • ملف قابل للتنفيذ app — الملف الثنائي الرئيسي.
  • \n
\n\n

لننشئ هيكل المستودع الأحادي:

\n\n
my_monorepo/\n├── Cargo.toml          # بيان 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

الخطوة 1. ملف Cargo.toml الجذر

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

الآن جميع الصناديق الثلاثة هي جزء من workspace واحد. سيقوم Cargo بإدارتها ككيان واحد.

\n\n

الخطوة 2. التبعيات الداخلية

\n

في ملف app/Cargo.toml، نحدد أنه يعتمد على مكتباتنا:

\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

الخطوة 3. كتابة الكود

\n

مثال على كود في core_lib/src/lib.rs:

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

في app/src/main.rs نستخدم هذه الدالة:

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

الخطوة 4. البناء والتشغيل

\n

الأوامر cargo build و cargo test و cargo run تعمل على workspace بأكمله. يمكن أيضًا تشغيل صندوق معين:

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

هذا هو الإعداد الأساسي. الآن ننتقل إلى الممارسات الأكثر تقدمًا.

\n\n

تنظيم متقدم: الوحدات (modules)، الاختبارات وإدارة الإصدارات

\n\n

عندما يزداد عدد الصناديق، من المهم الالتزام بالانضباط. إليك بعض النصائح العملية:

المدونات

توصيات الكتب