دامین دریون دیزاین، معماری لایه ایی

written on February 26, 2017

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

گفته شد که مراحل طراحی یک نرم افزار با روش ددد، با کشف و پیدا کردن زبانهای فراگیر در یک سیستم و سپس طراحی یک دامنه برای هر زبان فراگیر آغاز میشود. در این نوشتار قصد داریم به ساختار داخلی یک دامنه بپردازیم. دامنه ها می بایست به صورت مستقل از یکدیگر و با مفاهیم خاص خود طراحی شوند و سپس توسط مترجم ها به یکدیگر یا به دیگر سیستم های خارجی متصل شوند. باز هم تاکید می کنم که طراحی و ساختار هر دامنه باید مستقل از همه ی فاکتورهای خارجی انجام شود. این فاکتورهای خارجی نه تنها شامل دامنه های دیگر بلکه حتی شامل مسائل فنی و زیرساختی می باشند. برای به دست آوردن این استقلال، از تکنیک طراحی لایه ایی استفاده می شود. ایده ی اولیه طراحی لایه ایی را طراحان تحت عنوان Hexagonal Architecture با ترکیب الگوهای طراحی متفاوتی مثل پورت ها و آداپتورها (Ports and Adapters)، معکوس کردن وابستگی و … بیان کرده اند. ددد اما این مفهوم را گسترش داده و جزئیات بیشتری به آن می افزاید.

در ادامه ی این نوشتار، محدوده ی ذهنی ما داخل یک دامنه می باشد، به این مفهوم که وقتی از نرمافزار صحبت می شود در حقیقت منظور نرمافزاری است که در محدوده ی یک دامنه عمل می کند.

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

به عنوان مثال دیتابیسی را در نظر بگیریم که قرار است اطلاعات در آن ذخیره شوند. یک روش بسیار متداول در آغاز طراحی نرمافزار این است که نوع دیتابیس را در نظر بگیرند (به عنوان مثال Relational Database) و سپس به مدل سازی مفاهیم بر این اساس بپردازند. یعنی در حقیقت این دیتابیس است که مدل ها را تعیین می کند. حتی در خیلی موارد مسائلی مانند سرعت دسترسی به اطلاعات باعث تغییر چهره ی مدل می شود. فرض کنیم قرار است یک مفهوم مثل کاربر مدل شود. طراح پس از بررسی زبان فراگیر به این نتیجه می رسد که برای این مفهوم کافی است موارد زیر ذخیره شوند:

  • نام
  • نام خوانوادگی
  • شماره پرسنلی
  • تاریخ تولد
  • نشانی

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

بخش های متعلق به دامین مدل

از سوی دیگر مفاهیم مدل شده در ددد، برخلاف الگوهای مشابه که با نام مدل شناخته می شوند،‌تنها شامل حاملها و بسته های اطلاعات نمی شوند. بلکه شامل تراکنش ها و عملکردهای ممکن روی آنها نیز هستند. در مثال بالا، شی کاربر نه تنها شامل اطلاعات یک کاربر بلکه شامل تراکنشهایی مثل “کاربر نام خود را اصلاح می کند” یا “کاربر نشانی خود را عوض می کند” نیز می شود. اصولا ددد مخالف لخت کردن مدلها در حد صرفا حامل های اطلاعات (Anemic Domain Model) و مشوق مدل های چاق که حامل هردوی منطق و اطلاعات هستند می باشد. نکته ی ظریفی که درک آن بسیار مهم است، این است که باید دانست چه بخشی از منطق به داخل دامین مدل و چه بخشی به لایه های دیگر تعلق دارد. مارتین فولر منطق موجود در یک نرمافزار را به سه دسته ی منطق دامنه (Domain Logic)، منطق منبع اطلاعات (Datasource Logic) و منطق نمایش (Presentation Logic) تقسیم می کند. در مورد این سه دسته در نوشتارهای بعدی بیشتر صحبت خواهد شد اما از نظر او تنها منطق دامنه است که به درون لایه ی دامین مدل تعلق دارد. دو دسته ی دیگر منطق می بایست در لایه های دیگر قرار گیرند. منطق دامنه با نامهای دیگری مثل Business Logic، Calculation Logic و غیره هم شناخته می شود. در اینجا متوجه اشتباه و ضعف بسیاری از فریمورک های موجود که مشوق اشیا صرفا حامل اطلاعات و همچنین علت تاکید ددد در استقلال از فریمورک می شویم.

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

تصویر زیر مثالی از یک ساختار طراحی شده برای یک نرمافزار (دامین) می باشد که مهمترین مفاهیم مربوطه را نام می برد:

نمونه ایی از لایه های طراحی شده برای یک نرمافزار

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

تست نرمافزار

یکی دیگر از مزیت های طراحی لایه ایی، سادگی تست نرمافزار می باشد. به خصوص با دانستن اینکه ارزش اصلی نرمافزار در لایه های خاصی متمرکز شده می توان منابع تست را به صورت هدفمند و بهینه استفاده نمود. در نرمافزاری با چنین ساختاری، بیشتر تست های انجام شده بخش دامین مدل از کد را هدف می گیرند. به صورت کلی این بخش از نرمافزار با جدیت، اهمیت و پوشش بالا تست می شود و در تست لایه های بالاتر بیشتر به تست های مثبت عملکردی (Positive Functional Test) بسنده می شود.

توضیح و تشریح هریک از مفاهیم ذکر شده در دامین مدل موضوع نوشتار بعدی از این مجموعه می باشد.

Comments

Leave a comment

Previous comments

published on https://naghavi.me/blog/ddd-fa-layers
all rights reserved for Mohammad Naghavi