انتخاب معماری مناسب برای یک پروژه نرمافزاری، یکی از مهمترین تصمیماتی است که توسعهدهندگان در ابتدای کار با آن روبرو میشوند. سه الگوی معماری اصلی در این زمینه وجود دارد: مونولیت، مونو ریپو و مولتی ریپو. هر کدام از این الگوها مزایا و معایب خاص خود را دارند و انتخاب بهترین گزینه به عوامل مختلفی مانند اندازه پروژه، پیچیدگی آن، تیم توسعه و مقیاسپذیری مورد نیاز بستگی دارد.
معماری یکپارچه (Monolith)
معماری یکپارچه در ابتداییترین مراحل پروژه شما وجود دارد. این معماری دارای دو ویژگی اصلی است:
- یک کد بیس: این کد بیس تنها توسط یک مخزن گیت مدیریت میشود.
- وابسته: همهٔ قابلیتها، ابزارها و سرویسها به هم وابسته هستند.
ساختار دایرکتوری پروژه ممکن است به این شکل باشد:
├── assets
├── components
│ ├── Button.js
│ ├── Modal.js
│ └── ...
├── node_modules
├── pages
│ ├── Payment
│ │ └── ...
│ │ └── ...
│ ├── Shoping Cart
│ │ └── ...
│ │ └── ...
│ ├── Inventory
│ │ └── ...
├── utils
├── package.json
├── webpack.config.js
├── yarn.lock
└── README.md
مزایا
سادگی یک کد بیس باعث میشود تا توسعه، استقرار، تست و اشکالزدایی برای ما آسان شود.
معایب
معایب زمانی آشکار میشوند که برنامه بزرگتر و بزرگتر میشود.
- سرعت پایین توسعه و استقرار: ایجاد یک تغییر کوچک نیازمند کامپایل، استقرار و تست کل پلتفرم است که سرعت توسعه و استقرار را به شدت کاهش میدهد.
- قابلیت اطمینان پایین: یک خطای کوچک میتواند کل برنامه را از کار بیاندازد.
- قابلیت مقیاسپذیری پایین: همهٔ اجزا، توابع، سرویسها و ابزارها به هم وابسته هستند که مقیاسپذیری بخشهای مجزا را دشوار میکند.
- انعطافپذیری پایین: اگرچه پروژه توسط تیمهای زیادی نگهداری میشود، آنها باید از یک تکنولوژی مشابه (تک استک) استفاده کنند.
معماری مخزنهای چندگانه (Multi-repo)
فرض کنید سیستم پرداخت، سبد خرید و انبار را به سه مخزن گیت جداگانه تقسیم کنیم. این رویکرد به عنوان معماری مخزنهای چندگانه (مولتی ریپو) شناخته میشود.
ساختار نمونه برای هر مخزن:
// Repo1: Payment
├── assets
├── components
│ ├── PaymentButton.js
├── node_modules
├── pages
│ ├── main.js
├── package.json
├── webpack.config.js
├── yarn.lock
└── README.md
// Repo2: Shopping Cart
├── assets
├── components
│ ├── ShoppingCart.js
├── node_modules
├── pages
│ ├── main.js
├── package.json
├── webpack.config.js
├── yarn.lock
└── README.md
// Repo3: Inventory
├── assets
├── components
│ ├── InventoryComponent.js
├── node_modules
├── pages
│ ├── main.js
├── package.json
├── webpack.config.js
├── yarn.lock
└── README.md
همانطور که میبینید، معماری مخزنهای چندگانه برخی از مشکلات معماری مونولیت را حل میکند. با این حال، با چالشهای دیگری نیز روبرو خواهیم شد.
بزرگترین مشکل Multi-repo
- سختی در به اشتراک گذاری منابع مشترک (کامپوننتها، تنظیمات، ابزارها و مجموعه تستها): در معماری مولتی ریپو، به اشتراک گذاری منابع مشترک مانند کامپوننتها و ابزارها بین ریپوهای مختلف دشوار است.
راه حلهایی مانند استفاده از ساب ماژول گیت (git submodule) یا بستههای npm برای کپسولهسازی این منابع وجود دارد. با این حال، این کار میتواند پروژه را پیچیدهتر و مدیریت آن را دشوارتر کند.
مشکلات دیگر:
- فرایند بهروزرسانی خستهکننده: در این معماری، شما باید مخزن ابزارها، مخزن کامپوننتها و مخزن مجموعه تستها را به صورت جداگانه منتشر کنید و نسخههای این وابستگیها را به صورت دستی مدیریت کنید.
- دشواری در بازگشت به نسخههای قبلی: بدتر از آن، زمانی که میخواهید در محیط تولید به نسخههای قبلی برگردید، باید این کار را برای هر مخزن به صورت جداگانه انجام دهید.
معماری مخزن واحد (Monorepo)
به بیان ساده، معماری مخزن واحد (مونو ریپو) به شما امکان میدهد تا چندین پروژه را درون یک کد بیس واحد مدیریت کنید.
در این مثال، ۶ پکیج (بسته) وجود دارد:
- utils (ابزارها)
- components (کامپوننتها)
- services (سرویسها)
- payment (پرداخت)
- shopping-cart (سبد خرید)
- inventory (انبار)
هر پکیج، فایل package.json مخصوص به خود را دارد و وابستگیهای خودش را مدیریت میکند.
ساختار نمونه:
├── packages
│ ├── utils
│ │ ├── package.json
│ ├── components
│ │ ├── src
│ │ ├── package.json
│ ├── services
│ │ ├── package.json
│ └── ...
│ ├── payment
│ │ ├── components
│ │ ├── pages
│ │ └── package.json
│ │ └── node_modules
│ │ └── webpack.config.js
│ │ └── tsconfig.json
│ │ └── README.md
│ ├── shopping-cart
│ │ ├── components
│ │ ├── pages
│ │ └── package.json
│ │ └── node_modules
│ │ └── webpack.config.js
│ │ └── tsconfig.json
│ │ └── README.md
│ ├── inventory
│ │ ├── components
│ │ ├── pages
│ │ └── package.json
│ │ └── node_modules
│ │ └── webpack.config.js
│ │ └── tsconfig.json
│ │ └── README.md
├── node_modules
├── package.json
└── README.md
مزایا
-
سهولت در به اشتراک گذاری منابع و مدیریت وابستگیها: با استفاده از ابزارهایی مانند Lerna به راحتی میتوانید منابع مشترک را بین پکیجها به اشتراک بگذارید و نسخههای وابستگیها را مدیریت کنید.
-
صرفهجویی در زمان نصب وابستگیها: وابستگیهای مشترک میتوانند در دایرکتوری ریشه نصب شوند و هر پکیج نیازی به نصب مجدد آنها ندارد، در نتیجه زمان نصب کاهش مییابد.
-
مستقل و انعطافپذیر: هر پکیج علاوه بر وابستگیهای مشترک، میتواند وابستگیهای خاص خود را نیز داشته باشد. این امر مقیاسپذیری هر پکیج را تسهیل میکند.
معایب
-
کند شدن فرایند git pull: با بزرگتر شدن مخزن گیت، زمان pull کردن کد طولانیتر میشود. حتی اگر بخواهید فقط کد پکیج خودتان را pull کنید، مجبور هستید کد سایر پکیجها را نیز دریافت نمایید.
-
استقرار وابسته: حتی اگر فقط یک پکیج را بهروزرسانی کنید، مجبور هستید همه پکیجها را با هم استقرار دهید. ابزارهایی مانند Lerna میتوانند در شناسایی خودکار پکیجهای تغییر یافته و استقرار آنها به شما کمک کنند.
-
مشکل در اعطای دسترسی سطح پایین به گیت: از آنجایی که تمام کدها در یک مخزن قرار دارند، دسترسی گیت نیز به صورت کلی است. به نظر میرسد دادن دسترسی گیت به فقط یک پکیج امکانپذیر نباشد.
راهحلهای رایج برای مونو ریپو
- Pnpm
- Lerna
- Nx
معماری مونو ریپو (Mono-Repo) روشی برای مدیریت چندین پروژه در یک مخزن Git واحد است. این رویکرد مزایای زیادی مانند سهولت در اشتراکگذاری کد، مدیریت وابستگیها و همکاری تیمی را به همراه دارد. اما برای مدیریت موثر یک مونو ریپو، به ابزارهای قدرتمندی نیاز داریم. در ادامه به بررسی سه ابزار محبوب Pnpm، Lerna و Nx میپردازیم که به طور گستردهای برای مدیریت مونو ریپوها مورد استفاده قرار میگیرند.
Pnpm
Pnpm یک مدیر بسته نود است که به طور ویژه برای پروژههای مونو ریپو طراحی شده است. Pnpm با ایجاد یک سیستم فایل مشترک برای همه بستهها، فضای دیسک را بهینه میکند و زمان نصب وابستگیها را کاهش میدهد. برخی از ویژگیهای کلیدی Pnpm عبارتند از:
- نصب سریع و کارآمد: Pnpm با استفاده از یک سیستم فایل سخت لینک شده، وابستگیهای مشترک را فقط یک بار در سیستم نصب میکند.
- پشتیبانی از Workspaces: Pnpm به طور لوکال از Workspaces پشتیبانی میکند که به شما امکان میدهد چندین بسته را در یک مخزن مدیریت کنید.
- سازگاری با Yarn و npm: Pnpm با فرمتهای package.json Yarn و npm سازگار است.
Lerna
Lerna یک ابزار محبوب برای مدیریت مونو ریپوها است که توسط Babel ایجاد شده است که مخصوص ریپو های محتوی فایل جاوا اسکریپ و TS می باشد . Lerna به شما امکان میدهد چندین بسته را در یک مخزن مدیریت کنید و عملیاتهای رایجی مانند نصب، ساخت و انتشار را برای همه بستهها به صورت همزمان اجرا کنید. برخی از ویژگیهای کلیدی Lerna عبارتند از:
- مدیریت نسخههای بستهها: Lerna به شما امکان میدهد نسخههای مختلفی از هر بسته را مدیریت کنید و روابط وابستگی بین بستهها را تعریف کنید.
- پشتیبانی از چندین مخزن: Lerna میتواند برای مدیریت چندین مخزن نیز استفاده شود.
- انعطافپذیری بالا: Lerna به شما امکان میدهد تا کارهای سفارشی را با استفاده از پلاگینها و اسکریپتهای سفارشی ایجاد کنید.
Nx
Nx یک ابزار قدرتمند برای ساخت برنامههای بزرگمقیاس است که از معماری مونو ریپو پشتیبانی میکند. Nx به شما امکان میدهد تا برنامههای پیچیده را با استفاده از یک مجموعه ابزار یکپارچه بسازید، آزمایش کنید و استقرار کنید. برخی از ویژگیهای کلیدی Nx عبارتند از:
- پشتیبانی از چندین زبان و فناوری: Nx از زبانهای برنامهنویسی مختلفی مانند TypeScript، JavaScript، React، Angular و Node.js پشتیبانی میکند.
- زنجیره ابزار کامل: Nx یک زنجیره ابزار کامل برای توسعه، ساخت، آزمایش و استقرار برنامهها ارائه میدهد.
- پشتیبانی از معماریهای میکروسرویس: Nx به شما امکان میدهد تا معماریهای میکروسرویس را با استفاده از مونو ریپو پیادهسازی کنید.
کدام ابزار را انتخاب کنیم؟
انتخاب بهترین ابزار برای مونو ریپو به عوامل مختلفی مانند اندازه پروژه، پیچیدگی، زبانهای برنامهنویسی مورد استفاده و ترجیحات تیم توسعه بستگی دارد. در زیر خلاصهای از ویژگیهای هر ابزار آورده شده است:
ویژگی | Pnpm | Lerna | Nx |
تمرکز اصلی | مدیریت وابستگیها | مدیریت بستهها | ساخت برنامههای با مقیاس بزرگ |
زنجیره ابزار | محدود | متوسط | کامل |
پشتیبانی از زبانها | JavaScript
TypeScript |
JavaScript
TypeScript |
چندین زبان |
پیچیدگی | ساده | متوسط | پیچیده |
نتیجه گیری
در عمل، میتوانیم این سه معماری را با هم ترکیب کنیم:
- هر پروژه به عنوان یک معماری مونولیت: هر مخزن پروژه میتواند به عنوان یک معماری مونولیت عمل کند.
- پروژههای مستقل در مولتی ریپو: پروژههای مستقل مانند فرانتاند و بکاند تحت خطوط تجاری مختلف را در مخزنهای چندگانه قرار دهید.
- وابستگیهای مشترک در مونو ریپو: وابستگیهای مشترک مانند ابزارها، کامپوننتها، تنظیمات و سرویسها را در یک مخزن واحد (مونو ریپو) سازماندهی کنید.
مزایای این ترکیب:
- بهرهبرداری از مزایای هر معماری به طور همزمان.
- مدیریت بهتر پروژههای بزرگ و پیچیده.
- افزایش انعطافپذیری و مقیاسپذیری.
- کاهش پیچیدگی مدیریت.
نکات کلیدی:
- انتخاب بهترین معماری به عوامل مختلفی مانند اندازه پروژه، پیچیدگی، تیم توسعه و نیازهای کسبوکار بستگی دارد.
- ممکن است ترکیبی از معماریها برای پروژههای بزرگ و پیچیده مناسب باشد.
- مدیریت صحیح دسترسی به مخزنها و کنترل تغییرات در این ترکیب بسیار مهم است.
با در نظر گرفتن این عوامل و مزایا، میتوانید بهترین معماری را برای پروژه خود انتخاب کنید و فرایند توسعه نرم افزار خود را بهینه کنید .
دانشجوی مهندسی نرم افزار و علاقه مند به دواپس 🙂