امین برجیان
امین برجیان
خواندن ۱۰ دقیقه·۳ سال پیش

معماری شش‌ضلعی

ساختار شش‌ضلعی
ساختار شش‌ضلعی

ساختار شش‌ضلغی، یک ساختار طراحی معماری می‌باشد که اگر چه مزیت‌های زیادی می‌تواند داشته باشد، اما تقریبا از سال 2015 به بعد مورد توجه قرار گرفت. هدف اصلی که برای آن معماری شش‌ضلعی ارائه شده بود، این بود که این نوع معماری این اجازه را به ما می‌دهد تا یک برنامه به صورت مساوی توسط کاربران، برنامه، تست‌های خودکار یا اسکریپ‌های نوشته‌شده مورد استفاده قرار بگیرد و همچنین در عین حال به صورت کاملا مجزا نسبت محیط نهایی و دستگاه‌هایی که در آن اجرا می‌شود، قابلیت تست‌شدن و توسعه‌یافتن داشته باشد.

توضیحات بالا بسار جذاب و زیبا به نظر می‌آیند! همچنین در صورت عملی‌بودن توضیحات بالا، ما می‌توانیم به راحتی هسته‌ی اصله‌ی کسب و کار را از برنامه جدا کنیم و همچنین به راحتی رفتار برنامه را مستقل از هر چیز دیگری تست نماییم. امکاناتی که توسط این نوع طراحی معماری ارائه می‌شود به نیازمندی‌هایی که برای پیاده‌سازی معماری دامنه‌محور (Domain Driven Desgin) داریم بسیار نزدیک هست و به همین دلیل معمولا این موارد در کنار یکدیگر و با هم استفاده می‌شوند. اما با این حال این دو معماری، کاملا متفاوت هستند و هر کدام به تنهایی قابل پیاده‌سازی و استفاده هستند.

این معماری پیچیدگی خاصی برای پیاده‌سازی ندارد و می‌تواند به راحتی استفاده و مورد بهره‌برداری قرار بگیرد. در واقعیت این معماری بر مبنای تعدادی قواعد ساده و مشخص هستند که به راحتی قابل پیاده‌سازی و استفاده هستند. در ادامه به این موارد خواهیم پرداخت.

توضیحات ارائه‌شده در این مطالب، اکثرا ترجمه‌ی مطالب موجود در مراجع ارائه‌شده در انتهای این مقاله هستند.

اصول معماری شش‌ضلعی

معماری شش‌گانه بر پایه‌ی یکسری اصول و تکنیک‌ها ایجاد شده است که به صورت خلاصه در ابتدا بیان می‌کنیم:

  • در این طراحی به صورت مشخص (نه ضمنی) بخش‌های سمت سرور (server-side)، سمت کاربر (user-side) و منطق‌های کسب و کاری (Business Logic) از همدیگر تفکیک می‌شوند.
  • تمامی وابستگی‌ها بین سه بخش بیان شده به این صورت است که تنها بخش‌های سمت سرور و کاربر، به بخش مفاهیم کسب و کاری وابسته هستند. (وابستگی از سمت بخش مفاهیم کسب و کاری به بخش‌های سمت سرور یا کاربر وجود ندارد)
  • تمامی مرزهای بین بخش‌های مختلف بیان‌شده در بالا، از طریق پورت‌ها (Port) و آداپتورها (Adapters) فراهم می‌شود.

در ادامه از مفاهیم کسب و کاری، سمت سرور و سمت کاربر استفاده‌های فراوانی می‌شود. این مفاهیم بر اساس اسم‌های استفاده‌شده در مقاله‌ی اصلی معماری شش‌ضلغی می‌باشند.

جداسازی منطق‌های کسب و کاری از سمت سرور و کاربر

اولین و مهم‌ترین اصل در معماری شش‌ضلعی، جداسازی سه بخش اساسی به صورت مشخص از یکدیگر می‌باشد. این موارد را می‌توان در تصویر زیر نیز مشاهده نمود:

معماری شش‌ضلعی به صورت سطح بالا و نحوه‌ی ارتباط بخش‌های مختلف
معماری شش‌ضلعی به صورت سطح بالا و نحوه‌ی ارتباط بخش‌های مختلف

بخش سمت کاربر در سمت چپ

این بخش، در واقعیت همان بخشی می‌باشد که یا کاربر یا سامانه‌های خارجی که از سامانه‌ی ما استفاده می‌کنند، با برنامه‌ی ما تعامل و ارتباط برقرار می‌کنند. در واقعیت پیاده‌سازی‌هایی که این نوع ارتباطات را فراهم می‌کنند، در این قسمت قرار می‌گیرند. معمولا بخش رابط کاربری که توسط کاربر استفاده می‌شود (مثلا ارتباطات API با برنامه یا ورودی با فرمت کنسول) در این قسمت قرار می‌گیرند. به عبارتی در این قسمت ما استفاده‌کنندگان (actor) را می‌بینیم که از منطق‌های کسب و کاری استفاده می‌کنند. علت استفاده از نام سمت چپ نیز، به دلیل استفاده از همین مفهوم مشابه در مقاله‌ی اصلی این معماری می‌باشد.

بخش منطق‌های کسب و کاری در میانه

این بخش، در واقعیت همان بخش اصلی است که از سمت چپ و راست که استفاده‌کننده‌های آن هستند، به صورت مشخص جدا می‌شود. در واقعیت این بخش تمامی پیاده‌سازی‌های مربوط به منطق‌های کسب و کاری و نکات مرتبط به آن‌ها را در نظر می‌گیرد. در واقعیت همان واژگان کسب و کاری که قرار بوده در ابتدا توسط این سامانه مدل‌سازی و حل شود، در این قسمت از برنامه مشاهده می‌شود. معمولا یه متخصص در حوزه‌ی کسب و کار برنامه‌ی طراحی‌شده که معمولا فردی بدون بیشینه‌ی برنامه‌نویسی بوده یا شاید هم دانش حرفه‌ای در زمینه‌ی برنامه‌نویسی نداشته باشد، باید بتواند این بخش از برنامه را مشاهده کند و به راحتی به تناقض‌های میان آن و آن چه که باید برای حل مسئله مربوط کسب و کار خاص در نظر گرفته می‌شده است، اشاره کند. (در واقعیت ممکن است گاهی در مدل‌سازی مسئله بین مختصصان حوزه و تیم توسعه‌دهندگان، به دلایل مختلف تناقص‌هایی ایجاد شود)

بخش سمت سرور در سمت راست

در سمت سرور، در واقعیت تمام نیازمندی‌های برنامه برای این که برنامه قابلیت اجرایی‌شدن را داشته باشد، مشاهده می‌کنیم. اگر چه تعاملات با برنامه در سمت راست نشان داده شده است و تمامی منطق‌های کسب و کاری نیز در میانه آورده شده است، اما این که وضعیت سیستم به چه صورت نگهداری شود، ارتباطات با سرویس‌های خارجی لازم می‌باشد یا خیر، این که این وضعیت به چه صورت توسط تغییرات کاربر، تغییر می‌کند و ... همگی در این بخش پیاده‌سازی می‌شوند. به عنوان مثال یکی از نیازمندی‌های اصلی هر سامانه‌ای وجود پیاده‌سازی (منطق کد) برای ارتباط به لایه‌ی داده (مثل دیتابیس) می‌باشد که نحوه‌ و نوع فراخوانی‌های سمت لایه‌ی داده، ویژگی‌های فراهم‌شده توسط آن و ... در این بخش پیاده‌سازی می‌شود. به عنوان مثالی دیگر گاهی ممکن است که نیاز به ارتباطات در سطح شبکه (مثلا پروتکل HTTP) با دیگر سامانه‌ها باشد تا بتوانیم پاسخ کاربر را ارائه دهیم. این موارد نیز در سمت سرور پیاده‌سازی می‌شوند.

در واقعیت این بخش شامل استفاده‌کنندگانی (actor) می‌شود که توسط منطق‌های کسب و کاری مشخص‌شده، مدیریت می‌شوند. در مقاله‌ی اصلی از این بخش نیز به عنوان بخش سمت راست یاد شده است.

اهمیت این جداسازی بخش‌ها در چیست؟

اولین اهمیت جداسازی بخش‌های مختلف برنامه این هست که در واقعیت هر کدام از این بخش‌ها، مسئله‌های مختلفی را پاسخگو هستند. به عبارتی ما در هر زمانی می‌توانیم بر روی منطقی که باید متمرکز شویم، تمرکز کنیم و مستقل از بخش‌های دیگر تغییرات را اعلام کنیم. با جدابودن این بخش‌ها، فهم هر کدام از آن‌ها راحت‌تر خواهد شد و محدودیت‌های هر بخش تاثیر کمتری بر روی بخش‌های دیگر خواهد داشت.

نکته‌ی مهم دیگری که وجود دارد این است که ما منطق‌های کسب و کاری اصل و مبنای قرار داده‌ایم و بقیه بخش‌ها به آن وابسته هستند. به عبارتی این بخش به راحتی می‌تواند در یک پوشه یا ماژول جدا قرار گرفته و در اختیار تمام برنامه‌نویسان باشد. همچنین این بخش به راحتی می‌تواند تست شود بدون این که لازم باشد پردازش‌های سنگین دیگر بخش‌های سامانه اجرا شود. این بسیار مهم است چون در واقعیت آن چه که ما قرار بوده مدل کنیم و بر اساس آن مسئله را حل کنیم، همین مدل‌ها و منطق‌های کسب و کاری بوده است.

با توجه به توضیحات بالا، در عمل ما می‌توانیم بخش‌های مختلف سامانه را با تلاش حداقلی تست نماییم:

  • تست کل بخش کسب و کاری
  • تست ارتباط بین بخش کاربری و بخش منطق کسب و کاری مستقل از سمت سرور
  • تست ارتباط بین بخش سرور و بخش منطق کسب و کاری مستقل از سمت کاربر

وارونگی وابستگی در زمینه معماری شش‌ضلعی

قاعده‌ی وارونگی یکی از قواعد بسیار مهم می‌باشد که به اهمیت آن در زمینه برنامه‌نویسی شی‌گرا، آنکل باب (uncle bob) در کتاب خود نیز اشاره کرده بود. در بخش اصول توسعه سامانه‌های نرم‌افزاری چابک، او اشاره می‌کند که:

  • ماژول‌های سطح بالا نباید به ماژول‌های سطح پایین وابسته باشند، بلکه هر دو باید تنها به مفاهیم انتزاعی وابسته باشند.
  • مفاهیم انتزاعی نباید به جزییات وابسته باشند، بلکه جزییات باید به مفایهم انتزاعی وابسته باشند.

اگر کمی به این دو نکته‌ی اشاره‌شده دقت کنیم و طرح معماری شش‌ضلعی را دوباره نگاه کنیم، مشاهده می‌کنیم که همان سمت چپ و راست که در معماری شش‌ضلعی وجود دارد، در واقعیت نماینده‌ی دو استفاده‌ کننده‌ی مختلف هستند و به نوعی مفاهیم بالا در آن‌ها مشاهده می‌شود.

همان‌طور که در بالاتر، ارتباط بین بخش‌های چپ یا راست با قسمت مرکزی، از طریق پورت‌ها و آداپتورها ارائه می‌شود. به عبارتی بخش مرکزی تعدادی پورت (Port) را ارائه می‌دهد و بخش‌های دیگر برای اتصال به بخش مرکزی، از آداپتور (Adapter) مناسب استفاده می‌کنند. برای این که بتوانیم این مفاهیم و استفاده‌ی نکات بیان‌شده در بالا را در معماری شش‌ضلعی مشاهده و درک کنیم، در ادامه مثالی را بیان می‌کنیم تا مفاهیم روشن‌تر شوند.

فرض‌کنیم سامانه‌ای داریم که در آن قرار است هر شخصی بتواند یاد‌داشت‌های را با یک‌سری ویژگی‌های خاص بنویسید و در صورت نیاز لیست مواردی که تا الان نوشته است، دریافت کند. در هسته‌ی مرکزی ما مفهوم یادداشت و ویژگی‌های آن را به عنوان منطق کسب و کاری خواهیم داشت. در سمت چپ (سمت کاربر) به دنبال آن هستیم که کاربر بتواند یک یادداشت جدید اضافه کند یا لیست یادداشت‌ها را دریافت کند. در سمت راست (قسمت سرور) نیاز داریم تا یادداشت‌ها در یک پایگاه داده ذخیره شوند تا اطلاعات آن در هنگام خروجی‌گرفتن، وجود داشته باشند.

با فرض بر وجود مسئله‌ی بالا، ما نیاز داریم که از ورودی‌های استاندارد (مثل ورودی متنی) اطلاعات مربوط به یادداشت را دریافت کنیم تا در ادامه آن را ذخیره کنیم. منطق خواندن از ورودی استاندارد ممکن است به هر دلیل در آینده تغییر کند و همچنین نیاز سمت کاربر می‌باشد اما سمت کاربر مستقیما به سمت سرور دسترسی ندارد. در واقعیت سمت کاربر باید به نوعی به بخش منطق کسب و کاری وابسته می‌شود و از آن درخواست اضافه‌شدن یک یادداشت را می‌کند. اما در واقعیت این درخواست نیاز دارد به روشی اطلاعات یاداداشت را فراهم کند. به همین دلیل در سمت بخش میانی، یک واسط با نام NoteProvider ایجاد می‌شود که تامین‌کننده‌ی یک یادداشت می‌باشد. همچنین در سمت مرکزی تابعی برای اضافه‌کردن یک یادداشت (addNote) قرار می‌گیرد که از NoteProvider درخواست یک یادداشت می‌کند. سپس از واسط NotePersistent استفاده می‌شود تا این یادداشت را ذخیره کند. اما تمامی این واسط‌های هیچ پیاده‌سازی ندارند! در عمل این بخش‌های سمت کاربر و سمت سرور هستند که این پیاده‌سازی را فراهم می‌کنند. بخش سمت کاربر مثلا واسط NoteProvider را فراهم می‌کنند که امکان خواندن این اطلاعات را از فایل متنی فراهم می‌کند. (حتی می‌تواند در آینده تغییر کند تا از روش دیگری اطلاعات یادداشت دریافت شود) همچنین بخش سمت سرور پیاده‌سازی NotePersistent را فراهم می‌کند که به عنوان مثال داده را در دیتابیس mysql ذخیره کند. (در حالی که هر نوع پیاده‌سازی دیگری را در آینده می‌توان پیاده‌سازی نمود)

اگر مثال بالا را نگاه کنیم، مشاهده می‌کنیم که بخش مرکزی تنها یکسری واسط فراهم کرده است (مثل NoteProvider و NotePersistent) که در عمل مثل یکسری پورت در معماری شش‌ضلعی هستند. پیاده‌سازی این موارد در هر بخش به صورت مناسب فراهم می‌شود که این پیاده‌سازی در واقع همان آداپتور در معماری شش‌ضلعی می‌باشد.

وجود پورت‌ها و آداپتورها برای بخش‌های مختلف معماری شش‌ضلعی (منبع عکس)
وجود پورت‌ها و آداپتورها برای بخش‌های مختلف معماری شش‌ضلعی (منبع عکس)

اما همان‌طور که در مثال بالا مشاهده می‌کند، ما می‌توانستیم مثلا منطق ارتباط با پایگاه داده را در بخش مرکزی قرار دهیم و به راحتی از آن برای ذخیره‌سازی داده استفاده کنیم. اما به جای این نوع رفتار، ما یک واسط را در بخش میانه قرار دادیم و سپس بخش سمت سرور آن را پیاده‌سازی می‌کند. اما در عمل موقع ایجاد یک نمونه از بخش مرکزی، ما باید این واسط را با پیاده‌سازی مناسب ایجاد کنیم. این همان مفهوم وارونگی وابستگی‌ها هست که اگر چه هنوز وابستگی وجود دارد و باید فراهم شود، اما این وابستگی به صورت مستقیم در درون بخش میانه قرار نمی‌گیرد بلکه بعدا به صورت یک وابستگی تزریق می‌شود. این سبب می‌شود که به راحتی بتوانیم این بخش‌ها و پیاده‌سازی‌ها را از هم جدا کنیم. همچنین این امکان برای ما وجود دارد که در هر زمانی، پیاده‌سازی ساده‌تری از واسط را به جای پیاده‌سازی واقعی فراهم کنیم. این کاربرد در تست‌ها بسیار مهم می‌باشد.

نتیجه‌گیری

طراحی شش‌ضلعی یا نام دیگر آن، طراحی پورت و آداپتور یک طراحی شاهکارانه نیست که پاسخ‌گوی نیاز همه‌ی مسائل باشد اما با توجه به قواعد و اصولی که توسط این معماری مشخص شده است، پیاده‌سازی این سامانه در بدو کار و همچنین توسعه‌ی سامانه در ادامه‌ی کار، بسیار راحت‌تر خواهد بود. همچنین مزیت‌های چون سادگی استفاده از بخش‌های مختلف، وجود امکان تست هر بخش از سامانه به صورت مستقل، تمرکز بر مدل‌های کسب و کاری و ... همه از ویژگی‌های مفیدی هستند که این نوع معماری ارائه می‌دهد. در واقعیت این معماری اگر چه در ظاهر شاید کمی پیچیدگی را اضافه کند، اما اگر این پیچیدگی به درستی و با مراقبت، مدیریت شود، می‌تواند مزیت‌های بسیاری را برای سامانه و توسعه‌ی آن فراهم کند.

این مطلب، بخشی از تمرینهای درس معماری نرم‌افزار در دانشگاه شهیدبهشتی است.

منابع



معماری_نرم_افزار_بهشتیمعماریhexagonal
شاید از این پست‌ها خوشتان بیاید