Skip to content
العودة إلى المدونة
engineering6 دقيقة قراءة

Monorepo مقابل Polyrepo لفرق المنتجات: كيف تختار

دليل عملي بلا تعصّب للاختيار بين monorepo وpolyrepo، والأدوات التي تجعل أيّاً منهما ناجحاً لفريق منتجك.

SummationWorks
Monorepo مقابل Polyrepo لفرق المنتجات: كيف تختار

نادراً ما يتخذ فريق مكوّن من شخصين القرار نفسه الذي يتخذه فريق يضم خمسين مهندساً في هذه المسألة، وهذا هو جوهر الموضوع بالضبط: قرار الاختيار بين monorepo و polyrepo لا يتعلق بأي الأسلوبين هو "الصحيح"، بل بأي مجموعة من المقايضات يستطيع فريقك التعايش معها خلال العامين أو الثلاثة القادمة. إذا أخطأت الاختيار فستقضي عصاري أيام الجمعة في فك تشابك تعارضات الإصدارات أو تتبّع تغيير واحد عبر سبعة مستودعات. وإذا أصبت، فلن يفكّر معظم المطورين في الأمر أصلاً.

هذا قرار بنيوي يشكّل بهدوء تجربة المطور (developer experience)، وسرعة إصداراتك، ومدى سرعة تحوّل الموظف الجديد إلى عنصر منتج. وإليك كيف تفكّر فيه بعيداً عن التعصّب لأي طرف.

ما الذي يعنيه النموذجان فعلياً

يقوم نموذج monorepo بتخزين عدة مشاريع وتطبيقات ومكتبات مشتركة داخل مستودع واحد خاضع لإدارة الإصدارات. فتطبيق الويب وتطبيق الجوال وواجهة الـ API الخلفية ونظام التصميم المشترك، تعيش جميعها تحت سقف واحد بسجل commits موحّد. وهكذا تعمل Google وMeta وشريحة واسعة من منظومة الواجهات الأمامية الحديثة.

أما نموذج polyrepo (أو "multi-repo") فيمنح كل مشروع أو خدمة أو مكتبة مستودعها الخاص. فريق الجوال يملك مستودعاً، وخدمة المدفوعات تملك آخر، والموقع التسويقي يملك ثالثاً. ولكلٍّ منها سجلّه المستقل وصلاحيات وصوله وإيقاع إصداراته.

من المفاهيم الخاطئة الشائعة أن monorepo يعني monolith، وهذا غير صحيح. يمكنك تشغيل عشرات الخدمات القابلة للنشر بشكل مستقل داخل monorepo واحد، كما يمكنك بناء monolith شديد الترابط موزّع على خمسة مستودعات polyrepo. فبنية المستودع وبنية التشغيل قراران منفصلان.

أين يتفوّق نموذج monorepo

أقوى حجة لصالح monorepo هي التغيير الذرّي (atomic change). فحين تحتاج ميزة في الواجهة الأمامية إلى حقل جديد في الخلفية ونوع بيانات مشترك محدَّث، يستطيع طلب دمج (pull request) واحد أن يلمس الثلاثة معاً. يرى المراجعون الصورة الكاملة، ويختبر نظام الـ CI كل شيء مجتمعاً، ويصل التغيير كوحدة واحدة أو لا يصل. لا تنسيق لعمليات الدمج عبر المستودعات، ولا رقصة "انشر الـ API أولاً وإلا انهار كل شيء".

مزايا عملية أخرى:

  • إعادة استخدام الكود المشترك تصبح بسيطة للغاية. فالدالة المساعدة أو مكوّن الواجهة أو مخطط التحقق يُستورَد مباشرة بدلاً من نشره وترقيمه وجلبه كاعتمادية خارجية.
  • مصدر واحد للحقيقة في الأدوات. قواعد الـ linting والتنسيق وإعدادات TypeScript وخطوط الـ CI تُعرَّف مرة واحدة وتُطبَّق في كل مكان، فيتوقف الاتساق عن كونه معركة.
  • عمليات إعادة هيكلة واسعة أسهل. فإعادة تسمية API أو ترقية إطار عمل يمكن تنفيذها عبر كل المستهلِكين في حركة واحدة، لأن كل المستهلكين هناك في المكان نفسه.
  • سهولة الاكتشاف. يستنسخ المهندس الجديد مستودعاً واحداً فيرى المنظومة كاملة. وبالنسبة لفرق المنتجات في أسواق سريعة النمو مثل الخليج ومصر، حيث قد توظّف بوتيرة سريعة، فإن اختصار فترة التأقلم هذه يعني توفيراً حقيقياً في المال.

والثمن أن monorepo يتطلّب انضباطاً في الأدوات. فبدونه، يشغّل الـ CI كل الاختبارات في كل commit، وتصبح عمليات الاستنساخ بطيئة، ويتحوّل المستودع إلى ضريبة على كل عملية دفع للكود.

أين يتفوّق نموذج polyrepo

يتألق نموذج polyrepo حين تحتاج الفرق إلى استقلالية حقيقية. فإذا كان فريق الجوال يصدر وفق جدوله الخاص، وفريق البيانات يعمل بلغة Python بأدوات مختلفة تماماً، والموقع التسويقي تديره وكالة خارجية، فإن إجبارهم على مستودع واحد يخلق احتكاكاً بدل أن يزيله.

نقاط قوة polyrepo:

  • حدود ملكية واضحة. فلكل مستودع مالك بيّن، وصلاحيات وصول خاصة، وملف README خاص. ولا أحد يكسر بالخطأ خدمة لم يرها قط.
  • إيقاع إصدار مستقل. انشر خدمة المدفوعات ثلاث مرات في اليوم، والموقع التسويقي مرة في الشهر، دون طابور CI مشترك ودون عمليات نشر مترابطة.
  • عمليات استنساخ أصغر وأسرع. يبقى الاستنساخ والـ CI سريعَين لأن كل مستودع يحوي فقط ما يحتاجه فريق واحد.
  • تحكّم أبسط في الوصول. منح متعاقد خارجي صلاحية الوصول إلى مستودع واحد دون كشف قاعدة الكود بأكملها أمر مباشر.

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

الأدوات هي العامل الحاسم الحقيقي

كان معظم ألم monorepo التاريخي مشكلة أدوات، وقد تحسّنت الأدوات بشكل هائل. فإذا ملت نحو monorepo، فإن الفرق بين المتعة والمعاناة هو ما إذا كنت ستتبنّى نظام بناء مصمّماً له.

  • JavaScript وTypeScript: يتولّى Turborepo وNx تنسيق المهام والتخزين المؤقت ومبدأ "ابنِ ما تغيّر فقط". وتدير workspaces الخاصة بـ pnpm الاعتماديات بنظافة عبر الحزم.
  • القواعد البرمجية الأكبر أو متعددة اللغات: يقدّم Bazel وBuck عمليات بناء دقيقة وقابلة لإعادة الإنتاج، مقابل منحنى تعلّم أكثر انحداراً.
  • التخزين المؤقت البعيد وتشغيل الـ CI للمتأثّر فقط هما الميزتان اللتان تجعلان monorepo قابلاً للتوسّع. فحين يعيد الـ CI البناء والاختبار فقط للمشاريع التي لمسها commit فعلياً، قد يبدو monorepo الكبير أسرع من تشتّت مستودعات polyrepo.

وعلى جانب polyrepo، يذهب استثمارك إلى سجلّ حزم خاص، وتحديثات اعتماديات آلية، واختبارات تعاقد بين الخدمات بحيث يُكتشَف التغيير الكاسر في مستودع قبل أن يصل إلى آخر. العمل لا يختفي، بل ينتقل.

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

طريقة عملية للاختيار

تجاوز الأيديولوجيا وأجب عن بضعة أسئلة محدّدة:

  • كم من الكود مشترك فعلياً؟ كثرة المنطق المشترك ترجّح monorepo، والمنتجات المستقلة إلى حدّ كبير ترجّح polyrepo.
  • ما مدى ترابط جداول إصداراتك؟ الميزات التي تمتدّ عبر الواجهة والخلفية معاً ترجّح monorepo، ودورات النشر المستقلة ترجّح polyrepo.
  • ما حجم الفريق وكيف يُبنى؟ فريق منتج واحد يستفيد من monorepo، أما الفرق المستقلة المتعددة، خصوصاً عبر موردين أو مناطق زمنية مختلفة، فتفضّل غالباً polyrepo.
  • ما مدى شهيتك للأدوات؟ monorepo بلا نظام بناء مثل Turborepo أو Nx سيؤلمك. وإذا لم تستطع الالتزام بصيانة ذلك، فمِل نحو polyrepo.

بالنسبة لمعظم فرق المنتجات في مراحلها المبكرة والمتوسطة التي تبني تطبيق ويب وتطبيق جوال وAPI مترابطة، فإن monorepo واحداً بنظام بناء حديث هو الخيار الافتراضي العملي. أما المؤسسات شديدة الانفصال ذات المنتجات والموردين المستقلين، فيخدمها polyrepo عادة بشكل أفضل.

كما أنك لست محبوساً في خيارك إلى الأبد. فكثير من الفرق تبدأ بـ monorepo ثم تستخرج خدمة إلى مستودعها الخاص حين تستحقّ استقلالاً حقيقياً. الترحيل عمل، لكنه أسهل بكثير من التعايش مع البنية الخاطئة إلى ما لا نهاية.

أهم النقاط

  • بنية المستودع (mono مقابل poly) مستقلة عن بنية التشغيل (monolith مقابل microservices)، فلا تخلط بينهما.
  • نموذج monorepo يحسّن التغييرات الذرّية والكود المشترك والاتساق، لكنه يتطلّب أدوات بناء جادّة كي يتوسّع.
  • نموذج polyrepo يحسّن استقلالية الفرق ووضوح الملكية وعزل الإصدارات، مقابل عبء التنسيق وانحراف الإصدارات.
  • يتوقّف القرار على تجربة المطور واستعدادك لصيانة الأدوات المناسبة، لا على أي الأسلوبين أكثر رواجاً.
  • عند التردّد، يُعدّ monorepo واحد مع Turborepo أو Nx خياراً افتراضياً قوياً لفرق المنتجات المترابطة، مع إمكانية استخراج المستودعات لاحقاً إذا استحقّت خدمة ما الاستقلال.

اختيار البنية الصحيحة مبكراً يوفّر وقتاً ومالاً حقيقيَّين مع نموّك. في SummationWorks نُعدّ مستودعات monorepo وpolyrepo تناسب طريقة عمل فريقك فعلاً، لا الطريقة التي يقول بها مقال على الإنترنت إنها يجب أن تكون. استكشف خدماتنا، واطّلع على أعمالنا، أو تواصل معنا وسنساعدك على اختيار البنية والأدوات التي تُبقي فريقك يصدر باستمرار.

عن الكاتب

SummationWorks

SummationWorks is a software development company building web apps, mobile apps, and AI tools for startups and growing businesses across the US, UK, and GCC.

المزيد عنّا

لديك مشروع في ذهنك؟

لنحوّل فكرتك إلى برمجيات جاهزة للإنتاج.

ابدأ مشروعًا