معماری پیازی یک نوع معماری لایه ای ست که قابلیت نگهداری، تست پذیری و توسعه پذیری نرم افزارها را به آسانی برای شما فراهم میکند. این معماری تاکید زیادی روی وابستگی ها و جدایی منطق، عملیات ها، سرویس ها و رابط کاربری دارد. در این نوع معماری، هسته سیستم که پایین ترین و اساسی ترین لایه در این معماری ست، به هیچ کدام از لایه های دیگر وابستگی ندارد، و این لایه های دیگر هستند که به هسته سیستم از طریق اینترفیس ها وابستگی دارند. تعریف این معماری اولین بار در سال 2008 توسط Jeffrey
Palermo در وبلاگش ارائه شد، که البته مفهموم عجیبی نبود! ما قبلاً از معماری های لایه ای زیادی برای پیاده سازی نرم افزارها استفاده کرده بودیم، اما چیزی که در این معماری روی آن تاکید زیادی میشد، عدم وابستگی لایه های درونی به لایه های بالاتر با استفاده از اینترفیس ها بود. این معماری به شدت به مفهوم Dependency Inversion principle و تزریق وابستگی ها تکیه دارد.
یک پیاز را در نظر بگیرید. برای رسیدن به هسته پیاز، شما باید یکی یکی لایه های پیاز را بردارید. اساسی ترین نکته در این معماری، وابسته بودن کٌدهای خارجی به لایه های داخلی ست. هر لایه به لایه درونی تر وابسته است ولی لایه های درونی اجازه دسترسی به لایه های بالاتر از خود را ندارند. هر چقدر به لایه های داخلی این پیاز نزدیک تر شوید، وابستگی ها کمتر میشود. لایه های داخلی شما نباید به لایه های خارجی هیچ گونه وابستگی داشته باشند.
هسته سیستم شما را تشکیل میدهد. در این لایه موجودیت های Domain را تعریف کنید. مدل های اساسی سیستم که نرم افزار برای حل مسائل آن ها ساخته میشود در این قسمت قرار میگیرند. مفاهیم Domain-Driven Design در این معماری هم کاربرد دارند. Entityهایی که در اینجا تعریف میکنید نباید هیچ گونه وابستگی خارجی داشته باشند. کلاس های مدل باید به صورت POCO و تا جایی که میشود بدون کٌدهای سنگین و پیچیده نوشته شوند.
تعریف Entity : موجودیتی در سیستم که شامل قسمتی از داده های با ارزش ماست و با دیگر موجودیت های سیستم رابطه دارد.
در هسته سیستم شما باید قراردادهایی را بنویسید که لایه های خارجی تر موظف به پیاده سازی آن ها برای حل مسائل بیزنسی اپلیکیشن باشند. در واقع هسته سیستم شما نیازمندی های اپلیکیشن را تعیین میکند.
هر اپلیکیشنی شامل داده های با ارزشی است که نیاز به ذخیره و بازیابی دارد. گفتیم که موجودیت ها شامل این داده ها و روابط میان آن هاست که در لایه Core در قسمت Domain پروژه قرار میگیرند. Repositoryها لایه ای انتزاعی برای کار با داده های موجودیت های اپلیکیشن خواهند بود. بهتر است جوری این لایه را پیاده سازی کنید که به Storage خاصی وابسته نباشد. هنگامی که از ORMها برای لایه دسترسی به داده استفاده میکنید، جوری Repositoryها را بنویسید که از نوع دیتابیس یا محل ذخیره سازی داده های شما خبر نداشته باشد. این لایه باید متدهایی به لایه های بالاتر از خود ارائه کند که شامل پرس و جو، درج، بروز رسانی و یا حذف داده هاست.
این لایه شامل قراردادهای بیزنسی سیستم و پیاده سازی آن هاست. واسط میان UI و لایه Repository و شامل منطق سرویس های اپلیکیشن ماست. دستورات کاربر از طریق UI به این لایه میرسد، سرویس ها پس از اعتبارسنجی داده های کاربر، متدهای Repository را برای درج، بروز رسانی یا حذف داده ها صدا خواهد زد. بهتر است اینترفیس های این لایه را در یک پروژه دیگر قرار دهید تا UI شما به صورت مستقیم به پیاده سازی های سرویس ها وابستگی نداشته باشند. نام دیگر این لایه، لایه Application است که معمولاً در پروژه های بزرگ، خود شامل چند لایه است :
این لایه همان پوست پیاز است! لایه ای که کاربر مستقیماً با آن سر و کار دارد. البته این لایه حتماً UI نیست. مثلا در معماری ماکروسرویس، این لایه میتواند یک Web API باشد که در حال استفاده از لایه Services است. نکته ای باید در نظر بگیرید، عدم وابستگی این لایه به لایه های درونی تر، جز لایه Services است. در واقع این لایه، فقط باید به اینترفیس های لایه Services و البته DTOها وابستگی داشته باشد.
خٌب تا اینجا به بررسی لایه های مختلف معماری پیازی یا همان Clean Architecture پرداختیم و متوجه شدیم که مهمترین اصل در این معماری عدم وابستگی هسته سیستم به لایه های دیگر، و وابستگی لایه های خارجی به لایه های درونی تر از خود، میباشد. حالا میخواهیم، برای نمونه، ساختار یک پروژه را در قالب این معماری بسازیم. ببینیم به چه پروژه هایی نیاز خواهیم داشت. البته ساختار پوشه ها و نام گذاری ها پیشنهادیست، شما میتوانید از نام ها و ساختار سفارشی شده خود استفاده کنید، در صورتی که قوانین وابستگی ها را در این معماری رعایت کنید.
در ریشه پروژه خود، پوشه ای به نام core ایجاد کنید. این پوشه باید شامل Domain Models و اینترفیس های هسته سیستم شما باشد که هر کدام، در پوشه های جداگانه در پوشه core قرار خواهند گرفت. در کنار پوشه core یک پوشه دیگر در روت پژه خود بسازید به نام infrastructure که داخل این پوشه لایه services با زیرمجموعه های آن، و لایه Repository را در پوشه های مجزا بسازید. در نهایت برای ایجاد UI یا APIهای خود پوشه ای به نام presentation در روت پروژه بسازید و APIها یا UIهایی که اپلیکیشن شما ارائه میدهد در آن قرار دهید.
برای نمونه، میتوانید ساختار پروژه بِهلاگ (سیستم مدیریت محتوای وب سایت کُدباز که خودم نوشتم) را در اینجا بررسی کنید، که البته نه به صورت کامل، اما تا جایی که شده از قالب این معماری پیروی میکند.