ما هو الـ Monorepo؟

الـ Monorepo هو مستودع Git واحد يضم مشاريع أو خدمات متعددة، وقد يصل عددها أحيانًا إلى العشرات أو المئات. تخيّل قاعدة الشيفرة الداخلية لدى Google (التي تُدار من خلالها أنظمة Android وSearch وCloud وغيرها)، أو قاعدة شيفرة Meta التي تضم ملايين الأسطر موزعة على عشرات المنتجات. والنقيض من ذلك هو نهج المستودعات المتعددة (multi-repo): حيث يحصل كل مشروع على مستودعه الخاص.

قد يبدو المصطلح بسيطًا للوهلة الأولى، لكن الاختيار بين النهجين يصوغ سير عملك بالكامل: من طريقة مراجعة الشيفرة (code review)، إلى سرعات CI/CD، والتحكم في الصلاحيات، وحتى أسلوب تعاون فريقك.

الفوائد الحقيقية للـ Monorepo

تغييرات ذرّية عبر المشاريع

أبرز ما يميّز الـ Monorepo: حين تحتاج الخدمة A إلى تعديل واجهة الـ API الخاصة بها، وتحتاج الخدمة B إلى استهلاك تلك الواجهة في الوقت نفسه، يمكنك دمج التغييرين في عملية ذرّية واحدة (atomic transaction). لا وجود لحالة تسابق (race condition) تُدمج فيها B قبل A، ولا حاجة لعبارة "سنُصلح هذا في الـ sprint القادم". وهذا يتفوق على عالم المستودعات المتعددة، حيث يتطلب تنسيق التغييرات العابرة للخدمات إنشاء طلبَي دمج (PRs) منفصلين، وعمليتَي دمج، ويقظة بشرية دائمة لمراقبة التوقيت.

مثال: تضيف واجهة الـ API الخلفية حقلًا جديدًا إلى استجابة معينة، ويحتاج كل من تطبيق الويب وتطبيق الجوال إلى استهلاكه. في الـ Monorepo تنزل التغييرات الثلاثة معًا. أما في المستودعات المتعددة، فأنت تأمل أن يُدمج الـ PR الخاص بالـ backend قبل طلبات دمج الـ frontend، وإلا واجهت فرعًا رئيسيًا (main) معطّلًا مؤقتًا.

أدوات وتبعيات مشتركة

ملف .eslintrc واحد، وملف prettier.config واحد، وإعداد اختبارات موحّد على مستوى المستودع بأكمله. لا يتجادل المطوّرون حول إصدارات الأدوات في كل مستودع على حدة، بل يرثون التناسق تلقائيًا. وترقية Jest أو TypeScript تحدث مرة واحدة فتشمل كل شيء. كما تُطرح تصحيحات الأمان في المكتبات المشتركة بشكل موحّد.

أما المستودعات المتعددة، فتعني أن كل مشروع يصون أدواته الخاصة، ويقضي المطوّرون وقتًا في نقاشات "هل نُرقّي أم لا؟" داخل كل مستودع.

إعادة هيكلة أسهل

نقل الشيفرة بين الخدمات، واستخراج المنطق المشترك، وتوحيد الأدوات المساعدة المكررة، كل هذه مجرد عمليات commit في الـ Monorepo. أما في المستودعات المتعددة، فتتحول إلى تمارين تنسيق عبر طلبات دمج متعددة. وبالنسبة لقواعد الشيفرة سريعة التطور (الشركات الناشئة والفرق سريعة الحركة)، يتراكم هذا الاحتكاك ويثقل العمل.

رسم بياني واضح للتبعيات

بفضل أدوات مثل Nx أو Turborepo، يرسم الـ Monorepo بدقة أي خدمة تعتمد على ماذا. فتعرف حجم الأثر قبل أن تدفع تغييراتك (push). أما المستودعات المتعددة فتترك المطوّرين في حالة تخمين.

التكاليف الحقيقية للـ Monorepo

تعقيد وبطء الـ CI/CD

يتحوّل حجم الـ Monorepo إلى عبء عليه. فتغيير حرف واحد في وحدة (module) نادرة الاستخدام قد يؤدي، إن تُرك على حاله، إلى تشغيل اختبارات قاعدة الشيفرة بأكملها. ومستودع Monorepo يضم 50 خدمة ويختبرها جميعًا عند كل عملية دفع هو نهج بطيء ومكلف.

هذه المشكلة قابلة للحل (عبر الاختبار التفاضلي، والتخزين المؤقت للبناء باستخدام Nx أو Bazel أو Buck)، لكنها تتطلب استثمارًا. وكثيرًا ما تتجاهلها الفرق الصغيرة فتعاني من عمليات بناء تتجاوز 20 دقيقة.

عبء الأدوات

تتطلب مستودعات الـ Monorepo أدوات متخصصة. فأدوات مثل Nx وBazel وTurborepo وLerna قوية لكنها صعبة التعلّم والصيانة. قد لا يحتاج فريق صغير من أربعة أفراد إليها، بينما يحتاج فريق من 40 فردًا إليها قطعًا. وإذا فاتتك نافذة الاستثمار، تحوّل الـ Monorepo إلى مستنقع بطيء ومربك.

صداع التحكم في الصلاحيات

في المستودعات المتعددة، يمكنك منح المهندس X صلاحية الوصول إلى تطبيق الجوال دون خدمة الفوترة. أما في الـ Monorepo، فهو يحصل عادةً على قاعدة الشيفرة بأكملها (أو لا يحصل على شيء منها). ويتطلب التحكم الدقيق في الصلاحيات كتابة سكربتات مخصصة أو طبقة ثانية من فحوصات الصلاحيات داخل الـ CI.

وهذا أمر مهم للفرق الحريصة على الأمان وللمؤسسات الكبيرة. فوجود مطوّر مبتدئ لديه صلاحية الوصول إلى شيفرة المدفوعات في بيئة الإنتاج هو كابوس حوكمي.

تعارضات الدمج على نطاق واسع

عشرون مطوّرًا يدفعون تغييراتهم عبر عشرات المشاريع داخل مستودع واحد يعني وجود عدد أكبر من الفروع قيد العمل. والمزيد من التغييرات المتوازية يعني المزيد من التعارضات، خصوصًا في ملفات الإعداد المشتركة أو أدلّة الإصدارات. أما المستودعات المتعددة فتقلّص سطح التصادم.

قائمة القرار: أيهما تختار؟

اختر الـ Monorepo إذا:

  • كان فريقك صغيرًا إلى متوسط الحجم (من 2 إلى 30 شخصًا) ويعمل على منتج وثيق الترابط (تطبيق ويب + backend + تطبيق جوال يخدمون القاعدة نفسها من المستخدمين).
  • كانت التغييرات العابرة للخدمات متكررة بشكل طبيعي (مثل أن تستدعي تغييرات واجهة الـ API الخلفية تحديثات في الـ frontend).
  • كانت البنية التحتية أو المكوّنات المشتركة محورية في منتجك (نظام تصميم، مكتبة مصادقة، نماذج بيانات).
  • كنت مستعدًا للاستثمار في الأدوات (ولو بإعداد متواضع باستخدام Nx أو Turborepo).
  • كنت تتحكم في الصلاحيات (فريق داخلي، ومتطلبات الأمان خفيفة).

مثال واقعي: شركة ناشئة من خمسة أشخاص تبني منتج SaaS (واجهة React، وbackend بلغة Node، وأدوات مساعدة مشتركة). مستودع Monorepo واحد مع Nx يُبقي الجميع منسجمين، والتغييرات ذرّية، والأدوات متناسقة.

اختر المستودعات المتعددة إذا:

  • كان فريقك كبيرًا وموزّعًا (أكثر من 50 مهندسًا) أو لديك عدة فرق مستقلة بأولويات مختلفة.
  • كانت الخدمات ضعيفة الترابط (مثل خدمة backend يملكها الفريق A، وخدمة تحليلات يملكها الفريق B، دون اعتماد كبير لإحداهما على الأخرى).
  • كانت لديك احتياجات للتحكم الدقيق في الصلاحيات (المطوّرون المبتدئون لا ينبغي أن يروا بنية الإنتاج التحتية؛ والشركاء يحتاجون إلى وصول محدود إلى واجهات الـ API العامة).
  • كانت الخدمات تستخدم حِزَمًا تقنية شديدة الاختلاف (خدمة بلغة Python، وأخرى بلغة Go، وثالثة بلغة Node؛ يملك كل فريق حزمته التقنية ومستودعه).
  • كان النضج والعزل أهم لديك من التغييرات الذرّية (مثل إدارة خدمات مصغّرة microservices قابلة للنشر باستقلالية وإصدار مستقل).

مثال واقعي: شركة تقنية مالية (fintech) ناضجة لديها عشر خدمات (مدفوعات، KYC، تسوية، لوحة تحكم، تطبيق جوال). يملك كل فريق مستودع خدمته. ويتم التواصل بين الخدمات عبر واجهات الـ API. وعطل خدمة المدفوعات لا يستلزم إعادة اختبار لوحة التحكم.

النهج الهجين: Monorepo من الـ Monorepos

كثير من المؤسسات لا تختار أحد النهجين بشكل مطلق. بل تعتمد بدلًا من ذلك مستودع Monorepo لكل فريق أو مجال منتج. فيصون فريق الـ frontend مستودع Monorepo واحدًا (ويب، جوال، مكوّنات مشتركة)، بينما يصون فريق الـ backend مستودعًا آخر (خدمة API، خدمة worker، مكتبات مشتركة). ويتواصل المستودعان عبر واجهات الـ API أو عبر حزم خاصة مشتركة.

يمنحك هذا تغييرات ذرّية وأدوات مشتركة داخل الفريق الواحد، مع إبقاء الفرق منفصلة ومنع فوضى أحد الفرق من إصابة فريق آخر. وهو يتوسّع بشكل أفضل من الـ Monorepo الواحد عند تجاوز 500 مهندس، كما أنه أبسط من المستودعات المتعددة الصارمة إذا كانت لا تزال لديك بنية تحتية مشتركة.

الخلاصة

ليست مستودعات الـ Monorepo أفضل أو أسوأ بطبيعتها، بل هي مفاضلة (trade-off). فهي تمنحك تغييرات ذرّية، وتناسقًا، وسهولة في إعادة الهيكلة، مقابل تعقيد الـ CI وعبء الأدوات. وبالنسبة للفرق الصغيرة سريعة الحركة التي تبني منتجًا وثيق التكامل، تمثّل مكسبًا في الإنتاجية. أما بالنسبة للمؤسسات الكبيرة ذات الخدمات المستقلة والحدود الأمنية، فتتحول إلى عبء.

ابدأ من حجم فريقك وشكل منتجك. اسأل نفسك: "هل سنُجري بشكل متكرر تغييرات عبر عدة خدمات معًا؟" إن كان الجواب نعم، فمِل نحو الـ Monorepo. وإن كانت الخدمات مستقلة حقًا، فالمستودعات المتعددة تُبقي الأمور بسيطة. وإن كنت متردّدًا، فالنهج الهجين (Monorepo لكل فريق) يقسم الفرق بينهما، وغالبًا ما يكون الخيار الرابح عمليًا.

الخيار الأفضل هو ذلك الذي يتيح لفريقك التحرك بسرعة دون أن يتصارع مع أدواته.

ذو صلة: ما زلت تحسم أمر التطبيق نفسه؟ اطّلع على أصلي أم ويب أم هجين: كيف تختار طريقة بناء تطبيقك.