علیرضا ارومند
علیرضا ارومند
خواندن ۱۲ دقیقه·۴ سال پیش

قسمت سوم DDD - آشنایی با Bounded Context

1. مقدمه:

یکی از مشکل‌ترین و در عین حال ساده ترین مفاهیمی که با آن سر و کار داریم Bounded Context است که از این به بعد به اختصار به آن BC یا مرز مسئله می‌گوییم. BC محدوده‌ای منطقی است که، کاربردی و قابل اجرا بودن مدل دامنه را تعیین می‌کند. برای شروع به سراغ تعریف آقای Vaughn Vernon در کتاب IDDD می رویم:

مرز صریح و دقیقی که حول یک مدل دامنه وجود دارد.

تعریف آقای Eric Evans هم از این موضوع به شکل زیر است:

تلاش برای متحد کردن مدل در یک محدوده مشخص.

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

2. ارتباط با دامنه:

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

  1. دامنه: مجموعه ای از دانش‌های موجود
  2. مدل دامنه: تجرید شخصی از دامنه
  3. مرز مسئله: محدوده تعیین شده شخصی

3. اندازه مدل و مرز مسئله:

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

3.1. مدل دامنه بزرگ:

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

3.1.1. یک مدل اغراق آمیز:

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

3.1.2. مثالی از یک مدل بزرگ:

مدل سیستم بانکی
مدل سیستم بانکی

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

3.2. مدل دامنه کوچک:

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

3.3. انطباق زیر دامنه و مرز مسئله:

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

4. زبان و مرز مسئله:

مرز مسئله محدوده کاربردی بودن Ubiquitous Language را نیز تعیین می‌کند. همانطور که در مطلب قبلی گفته شد، UL مربوط به مدل دامنه است که خود مدل دامنه در یک مرز مسئله محصور شده است. در نتیجه زبان جهان شمولی که در مدل مسئله داریم بدون ریسکِ خطا و سوء برداشت در یک مرز مسئله قابل استفاده است. به محض خروج از مرز مسئله، ممکن است دیگر زبان جاری ما قابل استفاده نباشد. هر چند معمولا سعی می‌شود مرزها و مدل‌های دامنه محدودی داشته باشیم و زبان ما داخل این مرزها بدون مشکل قابل استفاده است، اما زمان‌هایی که چندین زیر مدل در یک مدل دامنه کنار هم قرار می‌گیرند ممکن است شرایطی ایجاد شود که استفاده از یک کلمه واحد زبانی معانی مختلفی را به ذهن متبادر کند. معمولا ایجاد چنین شرایطی برای ما نشانه‌ای است که باید مدل دامنه خود را تجزیه کنیم و مرزها را تغییر دهیم، اما به عنوان راه حلی به جز جدا سازی، در برخی موارد می‌توانیم از کلمات ویژه‌تر و اختصاصی تر در هر زیر مسئله استفاده کنیم تا اشتراک لغوی از بین برود.

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

5. مرزهای فنی:

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

اگر مرز مسئله به عنوان نگهدارنده اجزای فنی داخلی آن نیز در نظر گرفته شود به تعریف آن آسیبی نخواهد رسید.

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

6. ارتباطات و یکپارچه سازی:

هنگامی که یک مرز به مرزی دیگر وابستگی است، طبقه بندی روابط و رویکردهای یکپارچه سازی می‌تواند کمک کننده باشد. به همین منظور Vaughn Vernon و Eric Evans در کتاب‌های خوب راهکار‌ها و دسته بندی‌هایی را برای این موارد ارائه کرده اند. راهکارها و دسته بندی‌هایی مثل Open Host Services، Anti corruption Layer و Published Language که در کدام ویژگی‌ها و شرایطی را برای یک رویکرد ارتباطی و یکپارچه سازی شرح می‌دهند. در آینده راجع به این دسته بندی‌ها با جزئیات بیشتری صحبت خواهیم کرد. در حال حاضر فقط بدانید که موارد ذکر شده در بالا صرفا مربوط به ارتباط دو مرز و یکپارچه سازی آن‌ها است که هرکدام شرایط و ویژگی‌های خاصی را برای سیستم ایجاد می‌کند.

7. آشنایی با Context Map:

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

نمونه Context Map
نمونه Context Map


8. جمع بندی:

در این قسمت با مفهوم Bounded Context آشنا شدیم. تعریف BC محدوده منطقی حول مدل دامنه ایجاد می‌کند و قابلیت درک صحیح و استفاده صحیح از زبان را فراهم می‌آورد. در کنار آن می‌تواند ابزاری برای طراحی بهتر ساختار‌های فنی نرم‌افزار ایجاد کند.

ddddomain driven desingbounded contextcontext map
شاید از این پست‌ها خوشتان بیاید