معماری نرمافزار نقش مهمی در تعیین کیفیت، مقیاسپذیری و قابلیت نگهداری یک سیستم نرمافزاری ایفا میکند. یکی از الگوهای معماری که در سالهای اخیر محبوبیت قابلتوجهی پیدا کرده است، معماری پیازی نام دارد. این نوع معماری که با الهام از معماری لایهای و ششضلعی ایجاد شده است، رویکرد توسعه نرمافزار را انعطافپذیرتر و مقیاسپذیرتر میکند؛ اما معماری پیازی دقیقا چیست و بر چه اصولی استوار است؟ در این مقاله از بلاگ آسا در مورد این نوع معماری نرمافزار صحبت میکنیم.
معماری پیازی چیست؟
«جفری پالرمو» مهندس نرمافزار شرکت مایکروسافت اصطلاح معماری پیازی (Onion Architecture) را در سال ۲۰۰۸ ابداع کرد. معماری پیازی مبتنی بر یک مدل دامنه با لایههایی است که توسط رابطها به هم متصل شدهاند. از طرفی، انتیتیهای دامنه (Domain Entities) قلب و روح این معماری هستند. انتیتیها در طراحی دامنه محور (DDD) یک شی محسوب میشوند که شناسه مخصوص به خود را دارند.
زمانی که انتیتیهای دامنه و قوانین کسب و کار در معماری نرمافزار لحاظ میشوند، باید وابستگیهای خارجی را تا حد امکان از این اجزا دور نگه داشت. معماری پیازی بر جداسازی حوزههای مختلف نرمافزار بین مهمترین بخش یک برنامه تجاری، کد دامنه و جنبههای فنی آن مانند HTTP یا پایگاه داده تمرکز دارد. این همان چیزی است که توسعه و نگهداری نرمافزار و اعمال تغییرات جدید را راحتتر میکند. پلتفرمهای مایکروسافت یکی از نمونههای موفق پیادهسازی معماری پیازی هستند که هم با ASP.Net و هم با ویژوال استودیو (Visual Studio) سازگار هستند.
مزایای معماری پیازی
اصل کلی معماری پیازی این است که لایه نمایش رابطهای گرافیکی (اینترفیس لاجیک-Interface Logic)، لایه دسترسی به دادهها (دیتا اکسس لاجیک-Data Access Logic) و لایه تجارت (بیزینس لاجیک-Business Logic) را در هسته برنامه حفظ کرده و تمام وابستگیها را تا حد ممکن به بیرون منتقل میکند.
این نوع معماری نرمافزار یک هدف خاص دارد که آن جداسازی حوزههای مختلف نرمافزار است. معماری پیازی با تقسیم نرمافزار به لایههای مختلف به این جدایی دست مییابد و مزایای زیر را ارائه میدهد:
- لایه داخلی با لایههای خارجی وابستگی ندارند. درحقیقت، لایهها از طریق رابطها به هم متصل میشوند و این موضوع پیچیدگی را کاهش میدهد.
- تمام وابستگیهای خارجی مانند دسترسی به پایگاه داده و تماسهای سرویس در لایههای خارجی نمایش داده میشوند.
- از آنجایی که همه کدها به لایههای عمیقتر یا هسته وابسته هستند، معماری پیازی قابلیت نگهداری سیستم را افزایش میدهد.
- تستپذیری کلی کد افزایش پیدا میکند؛ زیرا Unit Test را میتوان برای لایههای مجزا نوشت بدون اینکه ماژولهای دیگر را تحت تاثیر قرار دهد.
- تغییرات در فریمورکها و فناوریها را میتوان بدون تاثیرگذاری بر هسته ایجاد کرد. به عنوان مثال، شما میتوانید به راحتی SQL را با MongoDB جایگزین کنید بدون اینکه روی هسته تاثیر بگذارد.
معایب معماری پیازی
در حالی که معماری پیازی مزایای متعددی را ارائه میدهد، معایب یا چالشهایی هم دارد. اجرای این نوع معماری به برنامهریزی دقیق و در نظر گرفتن وابستگیهای بین لایهها نیاز دارد. مدیریت این وابستگیها و اطمینان از جریان آنها از لایههای خارجی به لایههای داخلی میتواند پیچیدگی بیشتری را به پایگاه کد، بهویژه در اپلیکیشنهایی در مقیاس بزرگ، اضافه کند.
توسعهدهندگانی که با معماری پیازی آشنا نیستند ممکن است برای درک اصول آن به زمان نیاز داشته باشند. در برخی موارد، رعایت دقیق اصول این نوع معماری نرمافزار ممکن است به خصوص برای پروژههای کوچک یا کمتر پیچیده، منجر به مهندسی بیشازحد (Over Engineering) شود. معرفی بیشازحد لایهها میتواند زمان توسعه و پیچیدگی آن را به طرز قابلتوجهی افزایش دهد. همچنین راهاندازی این نوع معماری در ابتدا ممکن است به تلاش بیشتری نیاز داشته باشد و اجرای نادرست آن باعث افزایش پیچیدگی در فرایند توسعه نرمافزار میشود.
اصول معماری پیازی
هسته معماری پیازی شامل چندین لایه متحدالمرکز است که با یکدیگر ارتباط دارند. این لایهها براساس یکسری اصول پیکربندی شدهاند تا یک هسته قوی و منسجم را ایجاد کنند.
توسعه هستهای که هم پایدار و هم کارآمد باشد، برای پیادهسازی معماری پیازی در سیستم ضروری است. در ادامه به اصول این نوع معماری اشاره میکنیم:
وابستگی (Dependency)
لایهها، نماد سطوح مشخصی از مسئولیت هستند. لایههای بیرونی مکانیسمها خواهند بود (شامل ماژولهای قابل تغییر)، در حالی که لایههای داخلی اساس لاجیک بیزینس را تشکیل میدهند. لایههای بیرونی به لایههای داخلی متکی هستند، اما لایههای داخلی تحت تاثیر تغییراتی که در حلقههای بیرونی ایجاد میشود، قرار نمیگیرند. کلاسها، متدها، متغیرها و کد منبع لایههای بیرونی معمولا به لایههای درونی بستگی دارند، اما برعکس آن رخ نمیدهد. ساختارها و فرمتهای داده ممکن است در لایههای مختلف متفاوت باشند. لایههای داخلی نباید از فرمتهای داده لایه بیرونی استفاده کنند.
در یک کلام، لایههای درونی نباید به لایههای بیرونی وابسته باشند، اما لایههای خارجی میتوانند نسبت به لایههای داخلی وابستگی داشته باشند.
کوپلینگ (Coupling)
کوپلینگ میزان وابستگی متقابل بین ماژولهای نرمافزار است. کوپلینگ سست یا شُل به رابطهای اشاره دارد که در آن یک ماژول از طریق یک رابط ساده و پایدار با ماژول دیگر در تعامل است و نیازی به اجرای داخلی ماژول دیگر نیست.
کپسوله سازی دادهها (Data encapsulation)
هر لایه درونی یک رابط برای لایه بیرونی فراهم میکند. از طرفی، همه لایهها باید اطلاعاتی را ارائه دهند که لایههای داخلی به راحتی بتوانند آنها را مصرف کنند. ابتدا در لایههای عمیقتر، رابطهای انتزاعی را تعریف میکنیم، در حالی که این رابطهها را در لایه بالایی اجرا خواهیم کرد. با انجام این کارها میتوانیم توجه خود را به مدل دامنه حفظ کنیم و نگرانی خود را در مورد مسائل پیادهسازی کاهش دهیم.
جداسازی حوزههای نرمافزاری (Separation of Concerns)
برنامه به لایههایی تقسیم میشود که هر کدام وظایف و ویژگیهای مخصوص به خود را دارند. هر لایه در داخل برنامه به عنوان یک ماژول، بسته یا فضای نام (Namespace) عمل میکند.
لایههای معماری پیازی
معماری پیازی از مفهوم لایهها استفاده میکند و به شدت به اصل وارونگی وابستگی (Dependency inversion principle) متکی است. این اصل بیان میکند که ماژولهای سطح بالای برنامه باید مستقل باشند و به ماژولهای سطح پایین آن وابستگی نداشته باشند.
![لایههای معماری پیازی](https://blog.asax.ir/wp-content/uploads/2024/05/onion-architecture-layers.jpg)
رابط کاربری از طریق اینترفیسها با بیزینس لاجیک ارتباط برقرار میکند و چهار لایه زیر را تشکیل میدهد:
لایه انتیتیهای دامنه
لایه دامنه در قلب معماری پیازی قرار دارد و نشاندهنده اشیای تجاری و رفتاری است. همه اشیای دامنه باید در این هسته قرار گیرند. اگر برنامهای با فریمورک موجودیت (ORM) ساخته شده باشد، این لایه شامل کلاسهای (POCO) یا کلاسهای (Edmx) است. هیچ وابستگی بین انتیتیهای دامنه وجود ندارد. ممکن است علاوه بر اشیای دامنه، رابطهای دامنه هم موجود باشند. همچنین اشیای دامنه وابستگی یا کدهای پیچیده ندارند.
لایه مخزن
لایه مخزن (Repository) بین لایه انتیتیهای دامنه برنامه و لایه بیزینس لاجیک قرار میگیرد. معمولا باید APIهایی را در این لایه قرار دهیم که عملکرد ذخیره و بازیابی اشیا را با استفاده از پایگاه داده ارائه میدهند. در این لایه یک مخزن جنریک ایجاد میکنیم که منبع را برای دادهها جستجو میکند. همچنین دادهها را از منبع به یک انتیتی (موجودیت) بیزینس نقشهبرداری کرده و تغییرات را به منبع ردیابی میکند.
لایه سرویس
رابطهایی با عملکردها معمولی مانند افزودن، ذخیره، ویرایش و حذف در لایه سرویس نگهداری میشوند. این لایه برای بیزینس لاجیک استفاده میشود، زیرا حاوی منطقی تجاری برای یک انتیتی یا موجودیت است. رابطهای سرویس در این لایه حفظ میشوند تا از کوپلینگ سست و جداسازی حوزههای مختلف نرمافزار، اطمینان حاصل شود.
لایه رابط کاربری
لایه UI خارجیترین لایه است و شامل جنبههای جانبی مانند رابط کاربری و تستها میشود. این لایه نشاندهنده Web API یا Unit Test در یک برنامه وب است. این لایه اصل تزریق وابستگی (Dependency Injection) را پیادهسازی میکند و به برنامه اجازه میدهد ساختاری با پیوند آزاد طراحی کند. همچنین از طریق رابطها با لایه داخلی ارتباط برقرار میکند.
چالشهایی که معماری پیازی حل میکند
در معماری سنتی، تمام لایهها به هم پیوسته و به طور قابلتوجهی به یکدیگر وابسته هستند. به عنوان مثال، لایه رابط کاربری یا اینترفیس با بیزینس لاجیک ارتباط برقرار میکند و بیزینس لاجیک با دیتا اکسس لاجیک ارتباط دارد. این لایهها باید از هم جدا شوند، زیرا هیچ یک از لایهها در ساختارهای ۳ لایه مستقل نیستند. چنین سیستمهایی پیچیدگی زیادی دارند. بزرگترین عیب معماری سنتی کوپلینگ بیمورد آن است.
هدف اصلی معماری پیازی غلبه بر چالشهای مرتبط با معماری ۳ لایه و ارائه راهحلی برای مسائل معمولی مانند کوپلینگ سخت و جداسازی حوزهای نرمافزاری است. ما قبلا در مورد جداسازی حوزههای نرمافزاری به عنوان یکی از اصول معماری پیازی صحبت کردیم، اما بهتر است نگاه دقیقتری به تفاوت انواع کوپلینگ بیاندازیم.
کوپلینگ سست به این واقعیت اشاره دارد که یک شی میتواند از دیگری استفاده کند بدون اینکه به آن وابسته شود؛ اما کوپلینگ سخت به کلاسی گفته میشود که به شکلی محکم به کلاس دیگری متصل شده است. هنگامی که یک برنامه از پیچیدگی کمتری برخوردار باشد، ایجاد تغییرات چالشبرانگیز نیست. با این حال، وقتی صحبت از برنامههای کاربردی در سطح سازمانی میشود، ایجاد تغییرات با وجود کوپلینگ سخت بسیار دشوار خواهد بود.
کاربردهای معماری پیازی
معماری پیازی یک الگوی معماری کاربردی است که در انواع مختلف پروژههای نرمافزاری مورد استفاده قرار میگیرد.
![کاربردهای معماری پیازی](https://blog.asax.ir/wp-content/uploads/2024/05/onion-architecture-use-cases.jpg)
این سبک معماری در پروژههای زیر کاربرد دارد:
- اپلیکیشنهای سازمانی: این برنامهها در مقیاس بزرگ از معماری پیازی سود زیادی میبرند. این معماری با جداسازی حوزههای مختلف نرمافزاری و تغییرات در لایههای خاص، به حفظ و تکامل برنامه در طول زمان کمک میکند.
- برنامههای کاربردی وب (وب اپلیکیشن): برنامههای کاربردی سنتی ارائه شده توسط سرور یا برنامههای کاربردی تکصفحهای مدرن (SPA) با فریمورکهای سمت کاربر میتوانند از معماری پیازی برای سازماندهی پایگاه کد خود استفاده کنند.
- میکروسرویسها: در معماری میکروسرویسها، یک اپلیکیشن به چندین سرویس با اتصال آزاد تجزیه میشود. هر سرویس میتواند معماری پیازی خود را پیادهسازی کند تا مقیاسپذیری کلی سیستم را افزایش دهد.
- اپلیکیشنهای موبایل: اپلیکیشنهای موبایل از جمله اپلیکیشنهای بومی (Native-با نیاز به نصب روی دستگاه) برای iOS و اندروید، میتوانند از ساختار ماژولار معماری پیازی بهرهمند شوند. توسعهدهندگان با این معماری میتوانند از تستپذیری و نگهداری بهتر در پلتفرمهای گوشی همراه مطمئن شوند.
کلام آخر
اگرچه ممکن است در ابتدا پیچیده به نظر برسد، اما معماری پیازی در صنعت توسعه نرمافزار بسیار محبوب است. معماری پیازی رویکردی است که تکامل نرمافزاری را ساده میکند. این نوع معماری نرمافزار لایههای مشخصی دارد و ساختار واضحتری را به پایگاه داده میدهد. توسعهدهندگان جاوا ممکن است به اندازه توسعهدهندگان سی شارپ به معماری پیازی علاقه نداشته باشند. با این حال، تصمیم برای استفاده از معماری پیازی را باید به جامعه توسعهدهندگان و مهندسان واگذار کرد.
منابع:
www.bitloops.com | www.anarsolutions.com | www.clarity-ventures.com | blog.allegro.tech
دیدگاهتان را بنویسید