Hexagonal Architecture به زبان ساده

وقتی در مورد معماری شش ضلعی (Hexagonal Architecture) صحبت می‌شود همگی ذهنشان به سوی موضوعات متفاوت سفر می‌کند؛ اما در این پست قصد داریم نظر شما را به این موضوع جذاب، جلب کنیم. با وجود اینکه سالیان زیادی از معرفی معماری ششی ضلعی گذشته، اما در منابع فارسی کمتر به آن پرداخته شده است؛ پس تا انتهای این پست را با دقت بخوانید.از کجا شروع شد؟معماری شش ضلعی یا Hexagonal Architecture، یک الگوی معماری است که در طراحی نرم‌افزار، به‌دنبال حداقل نمودن وابستگی‌های داخلی کلاس‌ها به یکدیگر است به شکلی که تغییر در یک کلاس نیازی به تغییر در بقیه کلاس‌ها نداشته باشد. به این نوع از طراحی Loose coupling یا وابستگی ضعیف گفته می‌شود که باعث افزایش عمومیت، قابلیت نگهداری و پایداری کل سیستم خواهد شد. به‌طور خلاصه معماری شش ضلعی قابلیت ایجاد تغییرات در کد را افزایش داده و برنامه‌نویسی را ساده‌‌تر می‌کند.معماری شش ضلعی توسط دکتر آلیستِر کاکبِرن ایجاد شده است. دکتر کاکبِرن از سال 1991 در شرکت IBM مشغول به کار بود و برای ایجاد یک متدولوژی جدید و مدرن، شروع به مطالعۀ چگونگی موفقیت تیم‌های برنامه‌نویسی آن زمان کرد. تیم او یکی از معدود تیم‌هایی بود که در اواسط دهۀ 1990 در پروژه‌های تجاری اشیاء-فناوری موفق شد. کتاب او با عنوان دوام آوردن درپروژه‌های شئ‌گرا نشان داد که چگونه این کار را می توان انجام داد. دکتر کاکبِرن در ادامۀ تحقیقات خود، از جمله مشاور ویژۀ بانک مرکزی نروژ در اواخر دهۀ 1990، رویدادی را که صنعت نرم‌افزار را تغییر داد، یعنی نوشتن مانیفست توسعۀ نرم افزار چابک را سازماندهی کرد. او یکی از تاثیرگذارترین افراد در صنعت کامپیوتر و فناوری اطلاعات در دهۀ‌ 1990 بوده است که پیشنهاد می‌شود دربارۀ ایشان بیشتر تحقیق کنید.معماری شش ضلعی چیست؟هدف معماری‌های لایه‌ای سنّتی نرم‌افزار، ایجاد لایه‌‌هایی برای تفکیک نرم‌افزار است. یعنی هر لایه شامل ماژول‌ها و کلاس‌هایی است که مسئولیت‌های مشترک یا مشابهی دارند و برای انجام وظایف خاص با هم کار می‌کنند. انواع مختلفی از معماری‌های لایه‌ای وجود دارند و هیچ قانونی برای تعیین اینکه چند لایه لازم داریم، وجود ندارد. رایج‌ترین الگوی معماری 3 لایه است که در آن برنامه به لایۀ نمایش، لایۀ منطقی و لایۀ داده تقسیم می‌شود.پیروی از معماری لایه‌ای از بسیاری جهات سودمند است که مهم‌ترین آن‌ها تفکیک مشکلات می‌باشد. مثلاً یک توپ نخ را درنظر بگیرید. اگر بخواهید گره‌های آن را از هم جدا و توپ نخی را باز کنید، نمی‌توان همۀ گره‌ها و نخ‌ها را به‌صورت همزمان باز کرد. بلکه باید این گره‌ها و نخ‌ها را به‌صورت تفکیک شده و ترتیبی باز نمود. مشکلات ساخت یک نرم‌افزار هم شبیه به همین توپ نخ است.در سال 2005، دکتر کاکبِرن متوجه شد که تفاوت زیادی بین نحوۀ تعامل رابط کاربری و پایگاه دادۀ یک برنامه وجود ندارد، زیرا هر دو یک بازیگر خارجی هستند که با اجزای مشابهی که به روش‌های مشابه با یک برنامه تعامل دارند، قابل تعویض هستند. با نگاه کردن به این موارد، می‌توان بر روی ناشناس نگه داشتن این بازیگران خارجی تمرکز کرد و به آن‌ها اجازه داد تا از طریق پورت‌ها (درگاه‌ها) و آداپتورها (مقداردهی‌ها) تعامل داشته باشند؛ بنابراین از درهم‌تنیدگی و نَشتِ منطقی بین کسب‌وکار و اجزای خارجی جلوگیری می‌شود.اینجاست که به مفهوم معماری شش ضلعی می‌رسیم. معماری شش ضلعی که به آن معماری پورت‌ها و آداپتورها نیز گفته می‌شود، یک الگوی معماری است که به کاربران یا سیستم‌های خارجی اجازه می‌دهد تا از طریق یک آداپتور وارد برنامه در یک پورت شوند و خروجی برنامه را از طریق یک پورت به خارج ارسال کنند. چنین ساختاری یک لایۀ انتزاعی ایجاد می کند که از هستۀ برنامه محافظت نموده و آن را از ابزارها و فناوری‌های خارجی، و به نوعی نامربوط، جدا می‌کند. در ادامه به تشریح پورت‌ها و آداپتورها می‌پردازیم.پورت‌هامی‌توان به پورت‌ها از دیدگاه یک نقطۀ ورودی فناوری‌شناسی ببینیم؛ یعنی اینکه رابطی را تعیین می‌کند که به بازیگران خارجی اجازه می‌دهد تا با برنامه ارتباط برقرار کنند، صرف‌نظر از اینکه چه کسی یا چه چیزی رابط مذکور را پیاده‌سازی خواهد کرد. همانطور که یک پورت USB به چندین نوع دستگاه اجازه می‌دهد تا به کمک یک آداپتور USB، با یک کامپیوتر ارتباط برقرار کند. همچنین پورت‌ها به برنامه اجازه می‌دهند تا با سیستم‌ها یا خدمات خارجی مانند پایگاه‌های داده، کارگزاران پیام، سایر برنامه‌ها و غیره ارتباط برقرار کند.آداپتورهایک آداپتور تعامل با برنامه را از طریق یک پورت با استفاده از یک فناوری خاص آغاز می‌کند. برای مثال، یک کنترلر REST آداپتوری را نشان می‌دهد که به مشتری اجازه می‌دهد با برنامه ارتباط برقرار کند. در یک معماری می‌توان به تعداد مورد نیاز برای هر پورت، آداپتور درنظر گرفت بدون اینکه خطری برای پورت‌ها یا خود برنامه ایجاد کند.برنامهبرنامه هستۀ سیستم و شامل خدمات کاربردی است که عملکرد یا موارد استفاده را هماهنگ می‌کند. همچنین شامل مدل دامنه است که منطق کسب‌وکار بوده که در موجودیت‌ها، گروه‌های انباشته و غیره تعبیه شده است. همانند شکل زیر، برنامه توسط یک شش ضلعی نمایش داده می‌شود که دستورات یا کوئری‌ها را از پورت‌ها دریافت نموده و درخواست‌ها را از طریق پورت‌ها به دیگر بازیگران خارجی مانند پایگاه‌های داده نیز ارسال می‌کند.ممکن است برخی از خود بپرسند که چرا یک شش ضلعی؟ شاید فکر می‌کنند که تعداد لبه‌ها مهم است؛ جواب منفی است، اصلاً مهم نیست. حتی عدد شش هم مهم نیست. ایدۀ دکتر کاکبِرن از استفاده از یک شش ضلعی برای نمایش این معماری، صرفاً نمایش بصری ترکیبات چند پورت/آداپتور یک نرم‌افزار بوده است و همچنین نشان می‌دهد که چگونه سمت چپ برنامه، یا «محرک»، تعاملات و پیاده‌سازی‌های متفاوتی در مقایسه با سمت راست، یا سمت «متحرک» دارد. علاوه بر این، فضای کافی برای ترسیم پورت‌ها و آداپتورها به تعداد مورد نیاز وجود دارد. همچنین شکل باید عدم تقارن درون/خارجی را به جای بالا/پایین یا چپ/راست تداعی کند. بنابراین یک مربع یا مستطیل مناسب نیست و از طرف دیگر ترسیم پنج ضلعی، هفت ضلعی، هشت ضلعی و غیره خیلی سخت است؛ بنابراین شش ضلعی مناسب‌ترین شکل است.بازیگران محرک (یا اصلی) آن‌هایی هستند که تعامل را آغاز می‌کنند و همیشه در سمت چپ تصویر قرار می‌گیرند. به‌عنوان مثال، یک آداپتور محرک می‌تواند یک کنترل کننده باشد که ورودی (کاربر) را می‌گیرد و آن را از طریق یک پورت به برنامه ارسال می‌کند.بازیگران متحرک (یا ثانویه) آن‌هایی هستند که توسط برنامه وادار به تعامل می‌شوند. به‌عنوان مثال، یک آداپتور پایگاه داده توسط برنامه فراخوانی می‌شود تا مجموعه‌ای از داده‌های خاص را از مخزن واکشی کند.با توجه به چنین ساختاری، توسعه‌دهندگان باید نکات زیر را به هنگام پیاده‌سازی درنظر داشته باشند:پورت‌ها (بیشتر اوقات بسته به زبان منتخب) به‌عنوان رابط در کُد نشان داده می‌شوند.آداپتورهای محرک از یک پورت استفاده می‌کنند و یک سرویس برنامه رابط تعریف‌شده توسط پورت را پیاده‌سازی می‌کنند؛ در این مورد هم رابط پورت و هم پیاده‌سازی داخل شش ضلعی هستند.آداپتورهای هدایت شده، پورت را پیاده‌سازی می‌کنند و یک سرویس برنامه از آن استفاده می‌کند. در این مورد پورت در داخل شش ضلعی بوده اما پیاده‌سازی در آداپتور و بنابراین خارج از شش ضلعی است.از جمله موارد استفاده معماری شش ضلعی می‌توان به برنامۀ هشدار وقایع طبیعی اشاره کرد که معماری آن در شکل زیر آمده است. این برنامه دارای چهار پورت و چندین آداپتور در هر پورت است و وظیفۀ آن، گوش دادن به به هشدارهای خدمات هواشناسی ملی دربارۀ زلزله، گردباد، آتش‌سوزی و سیل و سپس اطلاع‌رسانی از طریق تلفن یا دستگاه‌های منشی تلفنی به مردم است. چرا باید از معماری شش ضلعی استفاده کنیم؟استفاده از معماری شش ضلعی، مزایای زیادی دارد که در ادامه به آن‌ها اشاره می‌شود:تست کردن را بهبود می‌بخشد: یکی از مزایای معماری شش ضلعی این است که می‌توان منطق برنامه و منطق دامنه را به‌صورت کاملاً قابل تست، ایزوله نمود. از آنجایی که این معماری به عوامل خارجی وابسته نیست، تست کردن آن آسان خواهد شد.نگهداری برنامه بهبود می‌یابد: سیستم‌های قابل نگهداری، سیستم‌هایی هستند که به راحتی قابل تغییر باشند. معماری شش ضلعی قابلیت نگهداری را افزایش می‌دهد زیرا جداسازی دغدغه‌ها و جداسازی منطق کسب‌وکار را فراهم می‌نماید که مکان‌یابی کُدی را که می‌خواهیم تغییر دهیم، آسان‌تر می‌شود. قابلیت نگهداری برنامه یک مفهوم بلندمدت مرتبط با بدهی فنی است. هرچه قابلیت نگهداری بیشتر باشد، بدهی فنی خواهد بود. بنابراین، معماری شش ضلعی بدهی فنی را کاهش می‌دهد.انعطاف‌پذیری افزایش می‌یابد: برای یک پورت معین، می‌توان چندین آداپتور داشت که هر کدام از یک فناوری خاص استفاده می‌کنند. برای انتخاب یکی از آن‌ها، فقط باید پیکربندی انجام شود که از کدام آداپتور برای آن پورت استفاده نمود. این پیکربندی می‌تواند به آسانی تغییر یک فایل خصوصیات پیکربندی خارجی باشد؛ یعنی بدون اصلاح کد، بدون کامپایل مجدد و بدون ساخت مجدد. به همین ترتیب، افزودن یک آداپتور فناوری خاص جدید به یک پورت، می‌تواند بدون دست زدن به کُد منبع موجود انجام شود زیرا آداپتور به تنهایی توسعه و کامپایل شده و در زمان اجرا، شناسایی می‌شود و به پورت متصل می‌گردد.برنامه مصون از تکامل فناوری خواهد شد: همواره فناوری بیشتر از منطق کسب‌وکار تکامل می‌یابد. در برنامه‌هایی که منطق کسب‌و‌کار با فناوری گره خورده‌اند، نمی‌توان تغییرات فناوری را بدون اصلاح منطق کسب‌وکار انجام داد. این امر مطلوب نیست، زیرا کسب‌وکار نباید تغییر کند. با معماری شش ضلعی، فناوری که می‌خواهید ارتقا دهید در یک آداپتور خارج از برنامه قرار دارد. پس فقط باید آداپتور را عوض کنید. خود برنامه تغییرناپذیر است زیرا به آداپتورها وابسته نیست.در تصمیم‌گیری‌های فنی تاخیر ایجاد می‌شود: وقتی یک تیم شروع به توسعه و کدنویسی می‌کند، می‌تواند فقط بر منطق کسب‌وکار تمرکز نموده و تصمیم‌گیری دربارۀ چارچوب و فناوری مورد استفاده را به تعویق بیندازد. این یعنی می‌توان بعداً یک فناوری را انتخاب نموده و یک آداپتور برای آن کدنویسی کرد.در مقابل، معماری شش ضلعی معایبی هم به‌همراه دارد که از جملۀ آن‌ها به موارد زیر اشاره کرد:باعث افزایش پیچیدگی می‌شود: یک پروژۀ نرم‌افزاری که معماری شش ضلعی را پیاده‌سازی می‌کند، ساختار پیچیده‌ای دارد که ماژول‌های زیاد و وابستگی‌های صریح بین آن‌ها تعریف شده است. منظور از ماژول ها، زیرپروژه های کُد برای جداسازی فیزیکی عناصر مختلف معماری است. حداقل یک ماژول برای شش ضلعی، یک ماژول برای هر آداپتور و یک ماژول برای راه‌اندازی کل پروژه وجود خواهد داشت. همچنین باید وابستگی‌های بین ماژول‌ها را تعریف شود. اگر زبان برنامه‌نویسی به معماری شش ضلعی اجازه ندهد که فقط پورت‌ها را در معرض دید قرار دهد، ماژول‌های بیشتری نیز وجود خواهند داشت. عملکرد فرایند ساخت ضعیف می‌شود: با توجه به پیچیدگی‌هایی که در قسمت قبلی تشریح شد، اگر پروژه خیلی بزرگ و با آداپتورهای زیاد باشد، فرایند کامپایل، اجرای تست‌ها، ساخت همۀ ماژول‌ها با هم و راه‌اندازی کل پروژه زمان زیادی می‌برد.اما پاسخ به این سوال که چه زمانی باید از معماری شش ضلعی استفاده کرد، همچنان نامشخص است. شاید بتوان گفت که «بستگی دارد». برای پروژه های کوچک، شاید درمان بدتر از بیماری باشد، به‌طوری که حل مشکلات بی‌اهمیت، سزاوار پیچیدگی اضافه شده توسط این معماری نیست و اصطلاحاً باید عطایش را به لقایش بخشید. برای پروژه‌های متوسط/بزرگ، که قرار است چرخۀ عمر طولانی داشته باشند و در طول عمرشان بارها اصلاح شوند، استفاده از معماری شش ضلعی در بلندمدت ارزشش را دارد.سخن پایانیمعماری شش ضلعی یا پورت‌ها و آداپتورها، یک نوش‌دارو برای هر درد و بیماری نیست. این معماری به هنگام پیاده‌سازی سطح معینی از پیچیدگی را به سیستم تحمیل می‌کند که وقتی با دقت از آن استفاده شود، مزایای زیادی برای سیستم را به‌همراه خواهد داشت.وقتی معماری شش ضلعی به درستی پیاده‌سازی شده و با سایر متدولوژی‌ها مانند طراحی دامنه محور ترکیب می‌شود، می‌تواند پایداری و گسترش طولانی‌مدت برنامه را تضمین نموده و ارزش زیادی برای سیستم و شرکت توسعه‌دهنده به ارمغان بیاورد.برای کسب اطلاعات بیشتر راجع به معماری شش ضلعی پیشنهاد می‌شود که مقالۀ اصلی دکتر کاکبِرن را مطالعه کنید. همچنین ایشان در وبسایت خود مطالب جالب و مفیدی قرار داده‌اند که دیدن آن‌ها خالی از لطف نیست.این مطلب به‌عنوان پاسخ برای بخشی از تمرین‌های درس معماری نرم‌افزار در دانشگاه شهید بهشتی نوشته شده است که امیدوارم از آن استفاده برده باشید.مراجع[1] Cockburn, A. (1998). Surviving Object-oriented Projects. Addison Wesley.[2] Cockburn, A. (2021). Hexagonal architecture. Alistair Cockburn. https://alistair.cockburn.us/hexagonal-architecture/ [3] Hexagonal Architecture - Ports ans Adapters Pattern. (2021). Hexagonal Me. https://jmgarridopaz.github.io/content/hexagonalarchitecture.html [4] Manifesto for Agile Software Development. (2001). Agile. http://agilemanifesto.org/ [5] Martinez, P. (2021, July 9). Hexagonal Architecture, there are always two sides to every story. Medium. https://medium.com/ssense-tech/hexagonal-architecture-there-are-always-two-sides-to-every-story-bc0780ed7d9c [6] Musib, S. (2019, December 17). A quick introduction to Hexagonal Architecture - Code Fountain. Medium. https://medium.com/thecodefountain/a-quick-introduction-to-hexagonal-architecture-484358c038b8 [7] Wikipedia contributors. (2021, July 26). Hexagonal architecture (software). Wikipedia. https://en.wikipedia.org/wiki/Hexagonal_architecture_(software)