مدتی است که تفکر طراحی دامنه محور یا Domain Driven Design در حوزه توسعه نرم افزار به شدت مورد توجه قرار گرفته است؛ رویکردی که به اختصار DDD نامیده میشود. در این مقاله از بلاگ آسا قصد داریم که در مورد تفکر و رویکرد DDD، آشنایی با مفاهیم آن و Subdomain, Domain, Bounded Context و Context Map صحبت کنیم. با ما همراه باشید.
DDD یا Domain Driven Design چیست؟
طراحی دامنه محور یا Domain Driven Design، برای اولین بار در سال ۲۰۰۳ در کتابی به همین نام و توسط اریک ایوانز (Eric Evans) مطرح شد و توجه جامعه نرمافزاری را به خود جلب کرد. در اصل DDD یک نوع تفکر یا رویکردی برای تولید و توسعه نرمافزارهای بزرگ، با فرایندها و قوانین زیاد و پیچیده است که از مرحله تحلیل تا کدنویسی یک محصول همراه ما است و در دو قسمت استراتژیک و تکنیکال به ما ایده میدهد.
البته اریک ایوانز در کتاب خود بیشتر به مفاهیم استراتژیک میپردازد و تمرکز اصلی او بر بیزینس یا حوزه اصلی نرمافزاری که میخواهیم بنویسیم، یعنی Domain است. در واقع کار DDD از یک خواسته یا مشکل کسب و کاری (Problem Domain) شروع میشود. او Domain را این گونه شرح میدهد:
«محدودهای که کاربر برای برنامه اعمال میکند.»
طراحی دامنه محور یا DDD بیشتر برای محصولاتی به کار میرود که کسب و کار پیچیدهای دارند و استفاده از آن در پروژههای کوچک و ساده، یا پروژههایی که صرفا نیاز به ذخیره و خواندن اطلاعات دارند و جنبه کسب و کار خاصی ندارند، ممکن است تنها زمان و هزینه پروژه را افزایش دهد و مزیت خاصی هم به همراه نداشته باشد.
کاربردهای DDD (طراحی دامنه محور)
DDD روی تعامل سازنده و بهینه میان برنامهنویسها و افراد متخصص دامنه یا Business Experts تاکید دارد. به همین دلیل ایجاد یک زبان مشترک به نام Ubiquitous Language در مورد مفاهیم دامنه، ضروری است. این زبان مشترک هم در مستندات تحلیل و هم در کد، دیده میشود. در اصل یکی از قدرتهای طراحی دامنه محور، استفاده از زبان مشترک است. برای مثال به دو تصویر زیر دقت کنید، تصویر اول یک سناریو برای ارسال و تحویل پیتزا و تصویر دوم پیادهسازی متد همین سناریو است. همان طور که میبینید، در هر دو تصویر سعی بر این است که از زبان مشترک استفاده شود.
مستند سناریو تحویل پیتزا:
پیادهسازی سناریو تحویل پیتزا:
در واقع DDD همه چیز را میشکند و به بخشهای کوچکتر تقسیم میکند تا برخورد با آنها سادهتر باشد؛ مثل Knowledge Crunching (شکستن دانش) یا شکستن دامنه به چند SubDomain یا ارائه راهکارهایی برای تقسیم نرمافزار به بخشهای جدا و مستقل از هم و تبیین ارتباط این بخشها با یکدیگر. این موضوع باعث میشود فرایند توسعه نرمافزار، به صورت موازی بین چند تیم انجام شود و همچنین معماران سیستم را قادر میسازد تا از معماریها و تکنولوژیهای مختلف در بخشهای مختلف استفاده کنند.
انواع Subdomain در طراحی دامنه محور
زیر دامنهها یا Subdomain به ۲ دسته تقسیم میشوند:
دامنه اصلی (Core Domain)
محدوده اصلی دانش و مسئله، دامنه اصلی نام دارد. بیشترین تلاش و هزینه هر شرکتی صرف دامنه اصلی میشود. بسیاری از شرکتها نیرویهای ماهر خود را به این بخش اختصاص میدهند و در اصل، Core Domain کلید موفقیت هر پروژه است.
دامنه پشتیبان و دامنه عمومی (Supporting Domain و Generic Domain)
در طول یک پروژه ممکن است با بخشهایی مواجه شویم که اصل کسب و کار را تشکیل نمیدهند ولی وجودشان برای این که کار اصلی دامنه انجام شود، ضروری است. ممکن است حتی این بخشها را از شرکتهای دیگر خریداری کنیم؛ مثل ارسال ایمیل یا اس ام اس و در واقع انتخاب subdomainها یک موضوع کاملا نسبی است که به تیم بستگی دارد و هیچ قاعده و قانون ثابتی ندارد.
مفهوم Bounded Context در DDD
همان طور که اشاره کردیم، Domain Driven Design همه چیز را میشکند. برای درک بهتر موضوع، به مکانیزم مغز انسان دقت کنید. وقتی مغز انسان با یک مسئله پیچیده روبهرو میشود، آن قدر مسئله را به بخشهای کوچک تقسیم میکند تا راه حل آن قسمتهای کوچکتر را در حافظهاش پیدا کند. بعد همه قسمتها را با هم ادغام میکند تا به جواب مسئله اصلی برسد. مفهوم Bounded Context یا محدودیت زمینه پژوهش، به محدودیتهایی اشاره دارد که باید در DDD به آنها توجه کنیم.
به عنوان مثال جمع دو عدد ۱۰۰+۱۰۰ را در نظر بگیرید. حاصل این مقدار برای خیلی از انسانها بدون استفاده از ماشین حساب بدیهی است؛ چون به عنوان یک مسئله بدون پیچیدگی برای مغز ثبت شده است. حال حاصل جمع ۱۵۷۸+۱۳۷۶ را در نظر بگیرید. بسیاری از افراد این جمع را یک مسئله پیچیده میدانند و در نگاه اول نمیتوانند به آن پاسخ دهند. در این حالت، مغز انسان برای حل این مسئله آن را به مسئلههای کوچکتر خرد میکند و در نهایت با ادغام مسئلههای کوچک، پاسخ را مییابد.
تعریف مسئله پیچیده به زبان ساده
منظور از مسئله پیچیده چیست؟ در واقع هر چیزی که درک آن در حوزه مسئله (Problem Space) برای مغز سخت باشد، یک مسئله پیچیده است. با توجه به تئوری پیچیدگی (Complex Systems Theory) به سیستمی پیچیده میگویند که از اجزای زیادی تشکیل شده باشد و این اجزا به هم وابستگی داشته باشند. به طور کلی SubDomainهای مختلفی در فضای مسئله (Problem Space) وجود دارند. در فضای راه حل (Solution Space) یعنی زمانی که میخواهیم این SubDomainها را به کد تبدیل کنیم، تبدیل به Bounded Context میشوند.
تفکر طراحی نرمافزار دامنه محور با استفاده از الگوهای استراتژیک و اصل خرد کردن، تلاش میکند که Domain پیچیده را به یک سری SubDomain با پیچیدگی کمتر تبدیل و وابستگی بین آنها را با شیوهای صحیح، مدیریت کند. در حالت ایدهآل، به ازای هر SubDomain یک Bounded Context وجود دارد ولی ممکن است در عمل این گونه نباشد.
ارتباط Bounded Context و SubDomainها
اریک ایوانز Bounded Context را به غشای سلول بدن تشبیه کرده است. همان طور که اگر غشای سلول از بین برود، دیگر سلولی وجود نخواهد داشت. او همچنین در کتاب خود، مثال فرش کردن یک واحد ساختمان را مطرح میکند.
اتاقها و سالن این ساختمان همان SubDomainها هستند و فرشی که برای آنها استفاده میشود همان Bounded Context است. در این مثال، میتوان برای هر اتاق یک فرش جداگانه در نظر گرفت (مورد ایدهآل) یا از یک فرش برای دو اتاقی که روبهروی هم قرار گرفتهاند، استفاده کرد (یک Bounded Context برای دو SubDomain) و این کاملا به فضای Domain بستگی دارد.
یک موجودیت در BCهای مختلف معناهای مختلفی میدهد و طبق این معنای متفاوت، رفتارها و ویژگیهای متفاوتی را هم به همراه خواهد داشت. برای مثال یک شرکت را در نظر بگیرید که از یک بیمه خاص استفاده میکند. یک فرد در حوزه شرکت به عنوان کارمند شناخته میشود و ویژگیهای خاص خود را دارد و همین فرد در حوزه شرکت بیمه به عنوان بیمهشده تلقی میشود و ویژگیهای متفاوتی از حوزه شرکت را به همراه دارد. هر BC معماری خاص خود را دارد؛ حتی میتواند دیتابیس مستقل داشته باشد و بسته به تصمیم شرکت، میتوان توسعه و پابلیش هر BC را به عهده تیمهای مختلف گذاشت.
ارتباط بین Bounded Contextها
Bounded Contextها با روشهای متفاوتی با هم در ارتباط هستند و از هم سرویس میگیرند. BC سرویسدهنده به عنوان UpStream شناخته میشود و BC سرویسگیرندهای که به رفتار یا دیتای UpStream وابسته است، به عنوان DownStream شناخته میشود. نوع ارتباطات بین BCها (محدودیت زمینه پژوهش) به موارد مختلفی تقسیم میشود که در ادامه به چند مورد از آنها اشاره میکنیم:
رابطه Seprate Ways
در واقع این همان ایده دوری و دوستی است! یعنی گاهی اوقات به دلیل هزینه بالای ارتباط بین تیمها یا همان Bounded contextها، شرکت تصمیم میگیرد که هر تیم راه خود را برود و روی هدف خود تمرکز کند.
رابطه Customer-Supplier
در این نوع ارتباط BC سرویسدهنده، به دنبال رفع نیازمندیهای BC سرویس گیرنده است و به نوعی آن را مشتری خود میبیند. به همین دلیل، نیازمندیهای BC سرویسگیرنده روی اولویتها و برنامهریزیهای تیم سرویسدهنده تاثیر میگذارد.
رابطه Conformist
در این نوع ارتباط، نیازمندیهای تیم سرویسگیرنده دغدغهای برای تیم سرویسدهنده ایجاد نمیکند، در واقع تیم سرویسگیرنده باید خودش را با تیم سرویسدهنده وفق دهد.
رابطه Partnership
در این نوع ارتباط، همکاری زیادی بین تیم سرویسدهنده و سرویسگیرنده وجود دارد و تفاوت آن با ارتباط Customer-Supplier در این است که تیم سرویسدهنده و سرویسگیرنده روی BCهایی کار میکنند که به دنبال یک هدف مشترک هستند؛ در حدی که حتی گاهی اوقات پابلیش آن دو باید با هماهنگی هم صورت بگیرد.
رابطه Anticorruption Layer
لایه ضدخرابی در واقع یک لایه مترجم سمت سرویسگیرنده است که از رخنه کردن مفاهیم و زبان BC سرویسدهنده به داخل BC خود جلوگیری میکند و در اصل، به عنوان نوعی فیلتر برای BC مطرح میشود (به نوعی الگوی Adapter است).
وقتی قسمتی از مدل بین BCها از نظر مفهوم و منطق یکسان باشد، آن را به عنوان یک بخش مشترک یا هسته مشترک در نظر میگیریم. این الگو حتما باید با وسواس و دقت خاصی مورد استفاده قرار بگیرد؛ چون باعث به وجود آمدن وابستگی میشود.
رابطه Published language
در اصل BC ارائهدهنده سرویس، یک مستندی از سرویسهای خود را در اختیار سرویسگیرنده قرار دهد.
رابطه Open Host Service
در این نوع ارتباط، سرویسدهنده سرویس مورد نظر خود را در جایی Host میکند و در قالب API به همراه یک مستند (Published language) در اختیار سرویسگیرندهها قرار میدهد. با توجه به مواردی که مطرح شد، وقتی از ارتباط بین BCها یک مدل تصویری غیر رسمی ایجاد میکنیم که نحوه ارتباط آنها را برای ما شفافتر کند، اصطلاحا Context Map ایجاد کردهایم.
جمعبندی
در این مقاله سعی کردیم با مفهوم طراحی دامنه محور یا Domain Driven Design آشنا شویم و اصول و قواعد آن را تا حد خوبی توضحی دهیم. در پروژههایی که نقش کسب و کار در آنها پررنگتر و فرایندها پیچیدهتر است، استفاده از DDD و تقسیم مسئله بزرگ به مسائل کوچکتر (SubDomain) میتواند کمک زیادی به فرایند حل مسئله داشته باشد.
دیدگاهتان را بنویسید