انتخاب بین مخزن یکپارچه (monorepo) و درخت‌های ماژولار یکی از تصمیمات کلیدی است که نحوهٔ توسعه، انتشار و نگهداری پروژه‌های بزرگ را تعیین می‌کند. بحث‌های عمومی در Hacker News و ردیت و تجربه‌های استخراج‌شده از نگهداری کرنل لینوکس نشان می‌دهد راه‌حل کارآمد معمولاً ترکیبی از سیاست‌ها و ابزارها است، نه صرفاً ترجیح به یکی از مدل‌ها.

تعاریف مختصر

  • مخزن یکپارچه (Monorepo): یک مخزن واحد که چندین پروژه، کتابخانه یا سرویس را در خود دارد و تاریخچهٔ مشترک برای کل کد فراهم می‌آورد. برای مرجع بیشتر: Monorepo در ویکی‌پدیا.
  • درخت‌های ماژولار / چند-مخزنی: هر پروژه یا مؤلفه در مخزن جداگانه نگهداری می‌شود و نسخه‌های وابستگی می‌توانند بین مؤلفه‌ها متفاوت باشند.

مزایای عملی مخزن یکپارچه

  • اعمال و بررسی تغییرات میان‌مؤلفه‌ای به‌صورت اتمیک ممکن است؛ یک pull request می‌تواند تمام اصلاحات لازم را شامل شود.
  • ردیابی رگرسیون ساده‌تر می‌شود، چرا که کد مرتبط در یک commit یا شاخهٔ واحد قرار دارد.
  • نیاز به اسکریپت‌های پیچیدهٔ هماهنگ‌سازی بین مخازن کاهش یافته و خطاهای ناشی از بازنگری‌های ناسازگار کمتر می‌شود.

معایب و هشدارهای عملی

  • استقرار مستقل همچنان واقعیت دارد: حتی با merge اتمیک، سرویس‌ها معمولاً روی زمان‌بندی و استراتژی rollout مستقل اجرا می‌شوند؛ بنابراین merge به‌تنهایی به معنای استقرار هم‌زمان همهٔ اجزا نیست.
  • حس کاذب اتمیک بودن: تیم‌ها ممکن است تصور کنند یک commit تمام سیستم را به وضعیت جدید می‌برد؛ اما بازگردانی جزئی و rollback برای مؤلفه‌هایی که مستقل deploy می‌شوند لازم است.
  • سیاست وابستگی سختگیرانه: monorepo معمولاً یک نسخهٔ واحد از هر وابستگی را تحمیل می‌کند که برای مؤلفه‌هایی با چرخهٔ عمر متفاوت مشکل‌آفرین است.

شناسهٔ آرتیفکت‌ها (تگ‌ها و هش‌ها) — مسئله و راه‌حل‌ها

وقتی PR شامل به‌روزرسانیِ مشخصهٔ انتشار است اما آرتیفکت ساخته‌شده (مثلاً تصویر کانتینر یا بسته) هنوز در دسترس نیست، باید راهی برای اشارهٔ امن و بازتولیدپذیر به آرتیفکت پیدا کرد. راهکارهای متداول:

  • دو مرحله‌ای کردن جریان تغییر: مرحلهٔ اول: ادغام کد و تولید آرتیفکت در CI که تگ یا هش را ایجاد می‌کند. مرحلهٔ دوم: commit یا PR خودکار که مشخصهٔ انتشار را با تگ واقعی به‌روز می‌کند و روند CD را تحریک می‌کند.
  • برچسب‌های موقت و پروسهٔ تبلیغ: ساخت آرتیفکت با تگ موقت، اجرای تست‌ها، ارتقاء به تگ انتشار و سپس به‌روزرسانی manifest.
  • منفک‌سازی مشخصه‌های انتشار: نگه‌داری manifestها به‌صورت اشیاء واقعی در یک دایرکتوری مشخص یا پایگاه‌داده انتشار که CI بتواند به‌صورت اتمی به‌روزرسانی کند.
  • امضای آرتیفکت و provenance: درج شناسهٔ ساخت و امضای دیجیتال آرتیفکت در مشخصهٔ انتشار برای تضمین آنچه قرار است استقرار یابد.

الگوی عملی پیشنهادی: GitOps صریح و مشخصه‌های انتشار ملموس

ترکیب مزایای monorepo با اصول GitOps و استفاده از «مشخصات انتشار reified» مؤثر است. اصول کلیدی:

  • هر مؤلفهٔ deployable دارای manifest مستقل (Helm chart، منیفست Kubernetes یا فایل release) باشد.
  • فقط وقتی manifest یک مؤلفه تغییر کند باید فرایند CD آن چرخش یابد؛ نه صرفاً به‌خاطر ادغام کد در نوک شاخه.
  • CI مسئول تولید آرتیفکت‌ها و نوشتن تگ تولیدشده به manifest به‌صورت خودکار و قابل رهگیری باشد.

چه چیز از مدل نگهداری لینوکس می‌آموزیم

مدل نگهداری کرنل لینوکس براساس تقسیم مسئولیت و سلسله‌مراتب نگهدارنده‌هاست: تغییرات ابتدا به زیرسیستم‌ها می‌رسد، آن‌ها مجموعه‌ای از patchها را در شاخهٔ خود نگه می‌دارند و سپس نگهدارنده‌های بالاتر و لینوس توری آن‌ها را ادغام می‌کنند. این ساختار امکان تقسیم مسئولیت، تست متمرکز برای هر زیرسیستم و نگهداری تطبیقی را فراهم می‌آورد. برای مرجع: کرنل لینوکس در ویکی‌پدیا.

درس‌های عملی برای پروژه‌های بزرگ

  • مسئولیت‌ها را شفاف تعریف کنید: صاحب هر مؤلفه مسئول manifest، تست و rollout باشد.
  • از سازوکارهای بررسی سلسله‌مراتبی بهره ببرید: نگهبانان زیرسیستم بررسی‌های اولیه را انجام دهند قبل از اینکه تغییرات به شاخهٔ عمومی بروند.
  • ابزارهای خودکار برای تولید، امضای آرتیفکت و به‌روزرسانی manifest به‌کار ببرید تا خطای انسانی کاهش یابد.

راهنمای تصمیم‌گیری

  • اگر تغییرات اتمیک میان‌مؤلفه‌ای زیاد و هماهنگی بین تیم‌ها پرهزینه است، monorepo مزیت دارد.
  • اگر مؤلفه‌ها چرخهٔ عمر، تیم یا وابستگی‌های جداگانه دارند، درخت‌های ماژولار منطقی‌تر است.
  • در بسیاری از موارد ترکیبی از دو مدل مناسب‌تر است: کد می‌تواند در مخزن واحد باشد اما مشخصه‌های انتشار و مکانیزم‌های CD باید صریح و مستقل مدیریت شوند.

قدم بعدی برای هر تیم مشخص است: چارچوبی برای manifestها تعریف و جریان CI/CD را حولِ تولید و نوشتن شناسهٔ آرتیفکت‌ها خودکار کنید؛ مرزبندی مسئولیت‌ها را شفاف سازید. این اقدامات از اشتباهات رایج در مسیر از کد تا اجرا جلوگیری می‌کند و امکان رشد مستقل مؤلفه‌ها را بدون از دست دادن هماهنگی فراهم می‌آورد.