معماری شش ضلعی با مثال‌های جاوا

1.معرفیدر این مقاله معماری شش ضلعی را بررسی خواهیم کرد. هدف اصلی این معماری نرم افزار بهبود قابلیت نگهداری و کاهش مدت زمانی است که شخص باید برای نگهداری و اصلاح کد خود در طولانی مدت صرف کند.معماری شش ضلعی به ما این امکان را می دهد که با اجازه دادن به جنبه های مختلف کد مستقل از یکدیگر، قابلیت نگهداری کد خود را افزایش دهیم. ارتباط با سیستم‌های خارجی، مدیریت دستورات و ارتباط بین این دو، همگی توسط تیم‌های مستقل (به لطف مرزهای بین لایه‌ها) قابل انجام است و همگی می‌توانند توسط یک سری از پورت‌های به خوبی ساخته شده به هم متصل شوند.2.بدهی فنی و ساختار شش ضلعییک مفهوم کلیدی در توسعه نرم افزار بدهی فنی است. در توسعه نرم افزار، تضاد مهمی بین راه حل های کوتاه مدت برنامه نویسی و برنامه برنامه نویسی بلند مدت وجود دارد. معمولاً کدهایی که در کوتاه مدت کمتر برنامه ریزی شده اند، در درازمدت منجر به کار توسعه اضافی می شوند. این کار اضافی به بدهی فنی معروف است و هدف هر برنامه نویس خوب کاهش هر چه بیشتر آن است. قابلیت نگهداری اصطلاحی است که برای توصیف آسان بودن نگهداری یک سیستم استفاده می شود. هر چه بدهی فنی کمتری داشته باشید، قابلیت نگهداری شما بیشتر است. معماری شش ضلعی برای افزایش قابلیت نگهداری کار می کند تا کد ما در دراز مدت به کار کمتری نیاز داشته باشد.همانطور که از نام آن پیداست، معماری شش ضلعی با یک شش ضلعی نشان داده می شود. شکل بالا کل شش ضلعی را نشان می دهد که هر یک از اضلاع نشان دهنده راهی است که سیستم ما می تواند با سیستم های دیگر ارتباط برقرار کند. به عنوان مثال، سیستم ما می تواند با استفاده از http، صابون، استراحت، sql یا یک پروتکل باینری و حتی با سایر سیستم های شش ضلعی ارتباط برقرار کند. اگر ما یک سیستم بزرگ داشتیم، می توانستیم آن را به چندین معماری شش ضلعی تقسیم کنیم که از راه دور با هم ارتباط برقرار می کنند. با این کار می توانید تیم برنامه نویسان را تقسیم کرده و توانایی آنها را برای کار موازی افزایش دهید.یکی دیگر از مزایای توسعه شش ضلعی انعطاف پذیری است که با آن می توانید تغییرات ایجاد کنید یا فناوری های جدید اضافه کنید. از آنجایی که هر لایه مستقل است، می توانید بدون نیاز به تغییر لایه های داخلی، تغییراتی در لایه بیرونی ایجاد کنید.3.داخل شش ضلعیداخل شش ضلعی ما از سه لایه تشکیل شده است: دامنه، برنامه کاربردی و چارچوب. معماری شش ضلعی برای Domain Driven Design مناسب است، چرا که ظاهرا خارج از دامنه ساخته می شود. در سه بخش بعدی به صورت جداگانه روی هر یک از لایه های داخلی تمرکز خواهم کرد.4.دامنهدامنه لایه مرکزی است که شامل تمام منطق تجاری و محدودیت های منطق تجاری است. لایه دامنه به روشی مستقل از فناوری به هر کاری که در معماری شما انجام می شود پاسخ می دهد.در مثال 1 زیر، محدودیتی وجود دارد که بررسی می کند آیا یک چرخ دنده خاص مجاز است یا خیر. اگر نیست،یک InvalidGearException پرتاب می شود. استثنا در تمام طول لایه چارچوبی که قرار است مدیریت شود ارسال می‌شود. برای مثال، چارچوب می‌تواند این استثنا را ثبت کند و آن را در قالبی خاص ارتباط دهد. ممکن است یک خطای SOAP یا یک پیام REST باشد که نشان دهنده خطای client است.public class Car implements Domain { [...]public void drive(Gear gear) { [...]if (isNotAllowed(gear)) {throw new InvalidGearException();} [...]}مثال 15.برنامهلایه برنامه بین دامنه و فریم ورک قرار می گیرد و امکان ارتباط بین دو لایه را فراهم می کند. علیرغم نام، این یک اپلیکیشن واقعی نیست، بلکه دستوراتی را که فریم ورک دریافت می کند و به دامنه ارسال می کند، اعمال می کند.می توان لایه برنامه را به عنوان مترجم بین آنچه در چارچوب و دامنه دریافت می شود تصور کرد یا برعکس. در مثال 2 زیر، کلاس CommandBusImpl دستوری را دریافت می کند که از لایه فریمورک ارسال شده است و آن را به دامنه ارسال می کند. در این مثال، CommandBusImpl از یک رجیستری، یک Design Pattern استفاده می‌کند تا بفهمد کدام دسته در دامنه قرار است دستوری را اجرا کند، و سپس execute() را بر روی آن کنترلر فراخوانی می‌کند.public class CommandBusImpl implements CommandBus {[...]public void execute(Command command) {registry.getHandler(command).execute();} [...]}مثال 2یک مثال از یک دستور می‌تواند یک انتزاع از DriveCommand باشد. برای این دستور ممکن است یک DriveHandler داشته باشیم که اگر آن دستور به متد execute ارسال شود، آن دستور هم ارسال می شود. توجه به این نکته مهم است که لایه برنامه اختصاصی دامنه نیست و همچنین مختص یک فرمت ارتباط خاص نیست. چه دستور در http ارسال شده باشد چه sql، برنامه به همان روش آن را مدیریت می کند.6.چارچوبلایه چارچوب لایه بیرونی معماری شش ضلعی است. ارتباطاتی را که از بیرون می آیند مدیریت می کند و ارتباطات بیرونی را به اشیایی منتقل می کند که می توانند در لایه های داخلی مورد استفاده قرار گیرند.public class HttpController extends BaseController {[...]public void process(HttpRequest request, HttpResponse response) {[...]commandBus.execute(new ommand(parameters));[...]} [...]} اگر ارتباطات http داشتیم، می‌خواهیم یک کنترل‌کننده در چارچوب ایجاد کنیم که بتواند اشیاء درخواست و پاسخ http را مدیریت کند. تابع زیر در کلاس HttpControllerپارامترها را از یک شیHttpRequest بازیابی می کند. در یک شیء Command پیچیده شده است، این پارامترها را به CommandBus ارسال می کند. در این گزیده کد نشان داده نشده است که چگونه شی HttpResponse در پایان متد به روز می شود.7.مروری کوتاه بر معماری شش ضلعیاز آنجایی که نگاه کردن به هر بخش از معماری شش ضلعی به طور جداگانه می تواند گیج کننده باشد، من قصد دارم لحظه ای را به طور خلاصه دوباره کل ساختار را مرور کنم. در خارج از شش ضلعی، ما ارتباطات خود را با سیستم مانند http، rest، باینری، soap یا شش ضلعی های دیگر داریم. ارتباطاتی که این سیستم‌های دیگر ارسال می‌کنند توسط چارچوبی دریافت می‌شوند که این ارتباطات را به اشیایی منتقل می‌کند که می‌توان روی آنها کار کرد. سپس برنامه دستور را از فریمورک دریافت می کند و آن را به کنترل کننده خاص خود در دامنه ارسال می کند. دامنه به روشی مستقل از فناوری به فرمان پاسخ می دهد و پاسخ خود را تا آخر به چارچوب ارسال می کند. سپس چارچوب این پاسخ مستقل از فناوری را به یک پاسخ وابسته به فناوری تبدیل می کند.8.دستورات (Use Cases)دستور (Command) یا Use Case عملیاتی است که سیستم ما می تواند انجام دهد، برای مثال "MakeCall"، "ReceiveCall" یا "SendSMS"، مستقل از یک فناوری خاص (soap, rest, http, binary ...). در حالی که یک تیم use cases را در یک سیستم ناتمام طراحی می کند، تیم دیگری می تواند رابط های فنی را برای مدیریت آنها پیاده سازی کند.9.پورت ها و آداپتورهامعماری شش ضلعی همانطور که در شکل زیر نشان داده شده است را می توان پورت ها و آداپتورها نیز نامید. هر پروتکل (http, rest, soap, sql, binary ...) که سیستم ما پشتیبانی می کند، یا هر طرف شش ضلعی، نشان دهنده یک "پورت" در داخل و خارج برنامه ما است. یک پورت به عنوان یک رابط نمایش داده می شود و یک شالوده‌ي پیاده سازی آداپتور آن پورت است. رابط (پورت) در یک لایه هست، پیاده سازی آن (آداپتور) در لایه داخلی بعدی است.10. مرزهادر معماری شش ضلعی هر لایه با یک مرز، خود را از لایه اطراف خود محافظت می کند. یک مرز لایه ها را تقسیم می کند و به هر یک اجازه می دهد تا مستقل عمل کند، می‌توانید آن را یک دیوار تصور کنید. این مرزها همه وابستگی ها را مجبور می کند که از بیرون به داخل بیایند.ما این کار را با وارونگی کنترل یا تزریق وابستگی انجام می دهیم، که به معنای استفاده از رابط های بیشتر است. به طور خلاصه، این بدان معناست که کلاس‌های service به صورت خارجی و بدون هیچ گونه اتصال مستقیم وصل می‌شوند - ارتباطات فقط بر اساس رابط‌های مستقل از فناوری است.در نتیجه، معماری شش ضلعی به ما این امکان را می دهد که با اجازه دادن به جنبه های مختلف کد مستقل از یکدیگر، قابلیت نگهداری کد خود را افزایش دهیم. ارتباط با سیستم‌های خارجی، مدیریت دستورات و ارتباط بین این دو، همگی توسط تیم‌های مستقل (به لطف مرزهای بین لایه‌ها) قابل انجام است و همگی می‌توانند توسط یک سری از پورت‌های به خوبی ساخته شده به هم متصل شوند.«این مطلب، بخشی از تمرینهای درس معماری نرم‌افزار در دانشگاه شهیدبهشتی است»