با وجود اینکه معماری hexagonal سالیان زیادی هست که وجود داره ولی من به این نتیجه رسیدم که منابع کمی برای پیادهسازی برنامهها به روش این معماری وجود داره. هدف از این مقاله پیادهسازی یک وباپلیکیشن با معماری hexagonal به وسلیهی جاوا و فریمورک اسپرینگ میباشد.
معماری hexagonal یا ساختار ports and adapters یک الگوی معماری است که در طراحی نرمافزار با هدف ساختن سیستمها به صورت Loosley coupled به کار میرود. به طور خلاصه این معماری قابلیت تستپذیری و قابلیت تغییر در کد را افزایش میدهد و قابلیت تغییر و یا جایگزینی بخشی از کد، ماژول و یا شئها رو برای برنامهنویس سادهتر میکند.
معماری hexagonal توسط Alistair Cockburn به منظور جلوگیری از دامهای ساختاری شناخته شده در طراحی سیستمهای شئگرا مثل وابستگیهای ناخواسته بین لایهها و همچنین ناخالصی کد رابط کاربری و منطق تجارت (business logic) ایجاد شده است و در سال ۲۰۰۵ منتشر شده است.
اگر دوست داشتین که در این بحث عمیقتر یاد بگیرید خوندن این کتاب بهتون توصیه میشه.
ویژگی اصلی معماری hexagonal برخلاف معماری رایج لایهای این است که وابستگیها بین کامپوننتها به داخل و به حوزهی آبجکت اشاره میکنند:
هگزاگونال در واقع یک روش تصور شده برای توصیف هستهی یک اپلیکیشن است که توسط دامین آبجکتها، usecaseهایی که آنها را عملیاتی میکنند و پورتهای input و output که یک رابط برای دستیابی به دنیای بیرون میباشند، است.
بیایید یک نگاهی به هر یک از کلیشههای این معماری بیاندازیم
دامین آبجکتها مثل آب حیات اپلیکیشن میمانند چرا که تمامی قوانین و منطق بیزینس در آنها پیادهسازی شده است. دامین آبجکتها میتوانند هم شامل حالتها و هم شامل رفتارها باشند. هرچقدر رفتارها به حالتها نزدیکتر باشند کد آن راحتتر فهمیده و نگهداری و بهروزرسانی میشود.
دامین آبجکتها هیچ وابستگیای به بیرون ندارند. آنها کد خالص جاوا هستند که یک API برای usecaseهایی که آنها را عملیاتی میکنند، فراهم میکنند.
چون دامین آبجکتها هیچ وابستگیای به لایههای دیگر ندارند، تغییرات در لایههای دیگر هیچ تاثیری روی آنها ندارد. آنها میتوانند آزاد از وابستگیها تکامل پیدا کنند. این بهترین مثال برای Single Responsibility principle (حرف S از SOLID) است، که بدین معناست که هر کامپوننت فقط باید یک دلیل برای تغییر داشته باشد. برای دامین آبجکت اون دلیل تغییر در نیازمندیهای بیزینس میباشد. معماری هگزاگونال یک روش خوب برای تمرین Domain-Driven Design میباشد.
با ساختن یک دامین آبجکت که با نام user profile شروع میکنیم:
همینطور که در کد بالا میبینید هیچگونه وابستگیای بین دامین آبجکت و سایر لایههای معماری وجود ندارد. البته در این کلاس پیچیدگی محاسباتی وجود نداره بنابریان کلاس فقط شامل فیلدها مورد نیاز ساختن یک پروفایل میباشد و یک سازنده و setterها و getterهای مورد نیاز در آن به کار رفته است. در صورتی که بتوانید فیلدها رو به صورت Object value تعریف کنید ساختار برنامه بیشتر به سمت DDD میرود.
برای ارتباط بین دامین و سایر لایههای معماری نیازمند پورتهای خروجی به لایهی persistence (برقراری ارتباط با دیتابیس) و ساختن پورتهای ورودی برای برقراری ارتباط از لایهی web که میتواند شامل کنترلرها یا sms یا هرگونه ارتباط خارجی دیگری باشد.
در کد بالا پورت مربوط به برقراری ارتباط دامین و عوامل خارجی که پایینتر کدش رو توضیح میدم رو مشاهده میکنید. پیادهسازی این کد در لایهی پورتهای خروجی به سمت persitence اتفاق میافتد.
در بخشی از این لایه پیادهسازی کدهای مربوط به لایهی پورت اتفاق میافتد و در بخشی دیگر ارتباط فضای بیرونی نرمافزار مثل کنترلرها و یا sms پیادهسازی میشوند.
پیادهسازی کدهای لایهی پورت نیازمند یک DTO (Data Transfer Object) برای برقراری ارتباط با ریپازیتوری و لایهی دیتابیس (persistence) میباشد.
و بعد از آن نیازمند آن هستیم تا ارتباط این DTO را با دیتابیس به وسیلهی یک ریپازیتوری برقرار کنیم.
و در نهایت در کلاسی که آن را آداپتر مینامیم، کدهایی که قبلا در پورت مربوط به دامین تعریف کرده بودیم را پیادهسازی و یا اصطلاحا override میکنیم.
در نهایت لایهی خارجی که در این مثال از کنترلر استفاده میشود را پیاده سازی میکنیم.
همانطور که در کدهای بالا دیده میشود در این معماری ما مستقیما در لایهی دامین تغییری ایجاد نمیکنیم و تمامی ارتباطهای ما به صورت غیرمستقیم و به وسیلهی پورتها و آداپترها کنترل میشوند.فولدربندی این معماری نیز به صورت زیر خواهد بود:
البته این معماری برای CRUD ساده (چیزی که در مثال بالا میبینید) خیلی بهینه نیست و فقط باعث افزودن پیچیدگی به سیستم میشود، بهتره از این معماری در سیستمهای بزرگ با بیزینس لاجیکهای بیشتر در لایهی دامین استفاده شود.