سلامی دوباره با بخش دوم Domain Driven Design
در بخش اول در مورد مفاهیم کلی و پایه ای DDD صحبت کردم، در این بخش تصمیم دارم در مورد دو مفهوم Bounded Context و Context Map صحبت کنم.
در بخش اول یک موضوعی رو عنوان کردم با مضمون اینکه هروقت از DDD صحبت شد یاد شکستن بیفتید. برای اینکه این موضوع رو بهتر درک کنیم به مکانیزم عمل کردی مغز انسان دقت کنید، وقتی مغز انسان با یک مسئله پیچیده روبه رو میشود آنقدر آن مسئله را به مسئله های کوچکتر میشکند که راه حل آن قسمت های کوچکتر را در حافظه اش داشته باشد، بعد همه قسمت ها را با هم ادغام میکند تا به جواب مسئله اصلی برسد. به عنوان مثال جمع دو عدد را در نظر بگیرید مثلا 100 + 100 حاصل این مقدار برای خیلی از انسان ها بدون استفاده از ماشین حساب بدیهی است چون به عنوان یک مسئله بدون پیچیدگی برای مغز ثبت شده است ولی حالا حاصل جمع 1578 + 1376 را در نظر بگیرید خیلی از انسان ها وقتی با این جمع رو به رو میشوند با یک مسئله پیچیده رو به رو شدند و در نگاه اول پاسخ این عبارت را نمیدانند در این حالت مغز انسان برای حل این مسئله آن را به مسئله های کوچکتر قابل حل خرد میکند و در نهایت با ادغام مسئله های کوچکتر پاسخ این مسئله را پیدا میکند.
حال منظور از مسئله پیچیده چیست؟ در واقع هرچیزی که درک آن در حوزه مسئله (problem space) برای مغز سخت باشد یک مسئله پیچیده است.
با توجه به تئوری پیچیدگی (Complexity Systems Theory) به سیستمی پیچیده میگویند که از اجزای زیادی تشکیل شده باشد و این اجزا بهم وابستگی داشته باشند.
به طور کل Sub Domain ها در فضای مسئله وجود دارند (Problem Space) که معادل آن ها در فضای راه حل(Solution Space) یعنی زمانی که میخواهیم این Sub Domain ها را به کد تبدیل کنیم تبدیل به Bounded Context میشوند.
تفکر DDD با استفاده از الگوهای استراتژیک و اصل خرد کردن تلاش میکند که Domain پیچیده را به یکسری Sub Domain با پیچیدگی کمتر تبدیل کند و وابستگی بین آن ها را درست مدیریت کند. با توجه به این تعاریف به این نتیجه میرسیم که Sub Domain ها در فضای مسئله وجود دارند (Problem Space) که در فضای راه حل(Solution Space) یعنی زمانی که میخواهیم این Sub Domain ها را به کد تبدیل کنیم تبدیل به Bounded Context میشوند. در حالت ایده آل اینگونه است که به ازای هر Sub Domain یک Bounded Context وجود داشته باشد ولی ممکن است در عمل اینگونه نباشد.
طبق تعریف آقای Bounded Context ،Eric Evans را به غشای سلول بدن تشبیه کرده است. در اصل این مرز برای این وجود دارد که پیچیدگی های هر Sub Domain به بیرون از آن نشت نکند همان طور که اگر غشای سلول از بین برود دیگر سلولی وجود نخواهد داشت. همچنین Eric Evans در کتاب خود مثالی از فرش کردن یک واحد ساختمان را زده است، که اتاق ها و سالن این ساختمان که قرار است فرش شوند همان SubDomain های ما محسوب میشوند و فرشی که برای آن ها استفاده میشود همان Bounded Context میباشد. در این مسئله، میتوان برای هر اتاق یک فرش جداگانه در نظر گرفت (مورد ایده آل) و هم از یک فرش برای دو اتاقی که رو به روی هم قرار گرفته اند استفاده کرد.(یک Bounded Context برای دو Sub Domain) و این کاملا به فضای Domain بستگی دارد.
یک موجودیت در BC های مختلف معناهای مختلفی میدهد و طبق این معنای متفاوت، رفتارها و خصیصه های متفاوتی را هم به همراه خواهد داشت. برای مثال یک شرکت را در نظر بگیرید که از یک بیمه خاص استفاده میکنند. یک فرد در حوزه شرکت به عنوان کارمند شناخته میشود و ویژگی های خاص خود را دارد و همین فرد در حوزه شرکت بیمه ای که از آن استفاده میکند به عنوان بیمه شده تلقی میشود و ویژگی های متفاوتی از حوزه شرکت را به همراه دارد.
هر BC معماری خاص خود را دارد حتی میتواند دیتابیس مستقل داشته باشد و حتی بسته به تصمیم شرکت میتوان توسعه و پابلیش هر BC را به عهده تیم های مختلف گذاشت. (عکس برگرفته شده از کتاب Practicing Domain driven design)
ارتباط بین Bounded Context ها
آن ها با روش های متفاوتی با هم در ارتباط هستند و از هم سرویس میگیرند. BC ای که سرویس دهنده است به عنوان UpStream شناخته میشود و BC ای که سرویس گیرنده است و به رفتار و یا دیتای UpStream وابسته است به عنوان DownStream شناخته میشود. نوع ارتباط های بین BC ها به موارد مختلفی تقسیم میشود که من چند مورد از آن ها را در این مقاله عنوان میکنم:
در واقع این همان ایده دوری و دوستی است. یعنی برخی اوقات به دلیل هزینه بالا ارتباط بین تیم ها و یا همان Bounded context ها، شرکت تصمیم به این موضوع میگیرد که هر تیم راه خود را برود و روی هدف خود تمرکز کند.
در این نوع ارتباط BC ای که به عنوان سرویس دهنده میباشد به دنبال رفع نیازمندی های BC سرویس گیرنده است و به نوعی آن را مشتری خود میبیند به همین دلیل نیازمندی های BC سرویس گیرنده برروی اولویت ها و برنامه ریزی های تیم سرویس دهنده تاثیر میگذارد.
در این نوع ارتباط نیازمندی های تیم سرویس گیرنده دغدغه ای برای تیم سرویس دهنده ایجاد نمیکند، در واقع تیم سرویس گیرنده خودش را باید با تیم سرویس دهنده وفق دهد.
در این نوع ارتباط، همکاری تیم سرویس دهنده و سرویس گیرنده در حد زیادی وجود دارد و تفاوت آن با ارتباط Customer-Suplier در این است که تیم سرویس دهنده و سرویس گیرنده برروی BC هایی کار میکنند که یک هدف مشترک را دنبال میکنند، در حدی که حتی گاهی اوقات پابلیش آن دو باید با هماهنگی هم صورت گیرد.
در واقع یک لایه مترجم سمت سرویس گیرنده میباشد که از رخنه کردن مفاهیم و زبان BCسرویس دهنده به داخل BC خود جلوگیری میکند. در اصل به عنوان نوعی فیلتر برای BC مطرح میشود.(به نوعی الگوی Adapter میباشد)
وقتی قسمتی از مدل بین BC ها از نظر مفهوم و منطق یکسان باشد آن را به عنوان یک بخش مشترک در نظر میگیریم. این الگو حتما باید با وسواس و دقت خاصی مورد استفاده قرار بگیرد چون باعث بوجود آمدن وابستگی میشود.
در اصل BC ای که ارائه دهنده سرویس میباشد به همراه سرویس، یک مستندی از سرویس های خود در اختیار سرویس گیرنده قرار دهد.
در این نوع ارتباط سرویس دهنده سرویس مورد نظر خود را در یک جایی Hostکرده و در قالب API به همراه یک مستند (Published language) در اختیار سرویس گیرنده ها قرار دهد.
با توجه به مفاهیم گفته شده در مورد Bounded Context ها وقتی از ارتباط بین BC ها یک مدل تصویری غیر رسمی ایجاد میکنیم که نحوه ارتباط آن ها را برای ما شفاف تر کند را اصطلاحا Context Map مینامیم.
جمع بندی: در این قسمت با مفهوم Bounded Context و Context Map آشنا شدیم.
تعریف BC محدوده منطقی حول مدل دامنه ایجاد میکند و قابلیت درک صحیح و استفاده صحیح از زبان را فراهم میآورد.