بررسی Domain Driven Design و رسالت آن در توسعه نرم افزار

پرووید

دسته های مقالات

در این پست از وبسایت پرووید در رابطه با بررسی Domain Driven Design و رسالت آن در توسعه نرم افزار صحبت خواهیم کرد.

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

بنابراین چیزی که ما به دنبال آن هستیم بحث با مشتری درباره نیازهای کسب و کار او است.
Domain Driven Design صرفا بر اساس این فرضیات برای ترسیم کردن نیازهای کسب و کار در مدل دامنه است. طراحی دامنه محور
همه چیز درباره چگونگی طراحی مدل دامنه شماست. به این معنا که هر کلاس دامنه باید یک رابطه مستقیم با  آنچه که در دامنه
کسب و کار است داشته باشد.

آموزش عملی و پروژه محور Domain Driven Design و CQRS سری آموزشی از وبسایت پرووید است که
در رابطه با Domain Driven Design و CQRS تنظیم شده است. پس از این دوره ی آموزشی می توانید از آموزش پیاده سازی اگلوی
CQRS در سی شارپ و بسته ی آموزش ویدئویی معماری CQRS در نرم افزار مباحث تئوری و کاربردی استفاده کنید.

در این پست از وبسایت پرووید می‌خواهیم در رابطه با Domain Driven
Design و ادعایی که در رابطه با ساختن نرم افزار ها دارد صحبت کنیم. Domain Driven Design یک استراتژی را برای ساختن نرم
افزارهایی که شدیداً رشد خواهند کرد و در طی زمان تکامل پیدا خواهند کرد را فراهم می کند. ادعای دیگر Domain Driven
Design این است که نرم افزار شما زیر بار فشار پیچیدگی یا Complexity کمر خم نخواهد کرد. شاید جالب باشد بدانید که
بسیاری از اصول Domain Driven Design با باورهای سنتی برنامه‌نویسی در تضاد است.

موضوع نگهداری نرم افزار و یا همان Maintenance از توسعه نرم افزار
و یا همان Development بسیار با اهمیت تر است. اگر نگهداری نرم افزار به درستی انجام نشود نتیجه کار نرم افزاری است که
همه از آن می‌ترسند. نرم افزاری که وقتی تغییر کوچکی در آن ایجاد می‌شود خروجی ش بسیار متفاوت و حتی شوکه کننده است. در
چنین شرایطی عملاً Maintenance نرم افزار متوقف می شود و برنامه نویس به سمت برنامه نویسی تدافعی یا همان Defensive
Programming سوق پیدا می‌کند. به عبارت دیگر به جای نگهداری نرم افزار کدهایی را در آن قرار می دهیم که از لحاظ ساختاری
یا همان Structural کاملا اشتباه هستند اما تضمین می‌کنند که کار نرم افزار به درستی انجام شود. ما اینگونه تغییرات بر
روی کدی که از قبل موجود است را وصله یا Patch نامگذاری میکنیم. نکته بسیار مهم در رابطه با این Patch ها که غیرساختاری
یا Non-Structural هستند این است که با وارد شدن آنها در نرم افزار به پیچیدگی نرم افزار افزوده می شود. نهایتاً نرم
افزار به حدی پیچیده می‌شود که عملا نگهداری آن غیر ممکن است و تصمیم گرفته می‌شود که نرم افزار به طور کامل کنار گذاشته
شود و یا از اول دوباره کد نویسی شود. بگذارید این چرخه یا Cycle را Create-Repair-Abandon-Replace یا همان CRAP بنامیم.
طبیعتاً معنی کلمات این سیکل خلق کردن-تعمیر کردن-کنار گذاشتن-جایگزین کردن است.

فرض کنید از شما به عنوان برنامه نویس خواسته اند که نرم افزاری را
تولید کنید که جایگزین نرم افزار دیگری خواهد شد. نرم افزاری که امکان نگهداری آن وجود ندارد. در واقع شما فاز آخر از
سیکل CRAP را انجام می دهید یعنی جایگزینی. در چنین شرایطی احتمال اینکه شما نیز نرم افزاری را تولید کنید که نهایتاً
کنار گذاشته شود و امکان نگهداری آن وجود نداشته باشد بسیار بالاست.

تکامل توسعه نرم افزار شکستن سیکل CRAP

پاسخ به این پرسش که سیکل CRAP را چگونه بشکنیم یک موضوع بسیار
مهم در روند تکامل نرم افزار و استراتژی‌های طراحی آن است. ما پیش از این در رابطه با نرم افزارهای Table-Driven
صحبت کردیم. در این نرم افزارها Logic مربوط به نرم افزار از Entity هایی که درون یک Table هستند استخراج و مشتق
می‌شود. در یک نرم افزار من از روش Table-Driven به شدت استفاده کردم و ناگهان متوجه شدم که من هرگز Complexity نرم
افزار را از بین نبرده ام. تنها کاری که کرده بودم این بود که Complexity نرم افزار را به Table های انتقال داده
بودم و از آنجایی که این نرم افزار پیچیدگی بالایی برای نگهداری داشت بعد از مدتی کنار گذاشته شد و جایگزین شد. در
فاز جایگزینی تصمیم گرفتم از نرم افزارهای قابل پیکربندی یا Configurable استفاده کنم. نرم افزار های Configurable
نسل بعدی نرم افزار های SAP هستند که پیاده سازی و پیکربندی آنها برای یک کمپانی خاص می تواند دو تا سه سال طول
بکشد. واضح است که این روش نیز روش مناسبی برای شکستن سیکل CRAP نبود. روش دیگری که به منظور شکستن سیکل CRAP
استفاده می‌شود اصول SOLID در نرم افزار های شی گرا است. اولاً بر اساس اصول SOLID ما ملزم هستیم که Functionality
جدید باید توسط کد جدید هندل بشود. به عبارت دیگر برای پیاده‌سازی Functionality جدید ما از نوشتن Patch بر روی
کدهایی که موجود هستند استفاده نمی‌کنیم. دوما تغییرات بر روی کدی که از قبل موجود است باید از بقیه نرم افزار
Isolated یا تفکیک شده باشد. متأسفانه اعمال اصول SOLID بر روی نرم افزار های بزرگ منجر به افزایش شدید تعداد Object
می شود. این افزایش شدید باعث می شود که برنامه نویسانی که جدیدا قصد دارند بر روی پروژه کار کنند دچار ابهام و
سردرگمی شوند. اگر بخواهم به طور خلاصه بگویم اغلب استفاده از اصول SOLID پیچیدگی نرم افزار را از بین نمی برد بلکه
آن را از Object ها به Architecture منتقل میکند.

یکی دیگر از روش هایی که سعی به شکستن سیکل CRAP می کند
ریفکتورینگ است. ریفکتورینگ به برنامه نویس این امکان را می‌دهد تا تغییرات درونی و ساختاری یا همان Structural را
به جای اعمال کردن Patch های در زمان نگهداری نرم افزار اعمال کند. زمانی که ریفکتورینگ در کنار Test Driven
Development استفاده می‌شود می‌تواند کیفیت کد یا همان Code Quality را حفظ و یا حتی آن را بهبود ببخشد. این کیفیت
کد زمانی که تغییراتی بر روی کد ایجاد می‌کنیم دست نخورده باقی می ماند. البته اغلب مدیر پروژه می‌تواند با
ریفکتورینگ مخالف باشد چون ریفکتورینگ نیاز به هزینه های زمانی و مالی دارد و اغلب بر روی خروجی نهایی نرم افزار
اثری نمی‌گذارد. به عبارت دیگر ممکن است شما مدیری را در پروژه داشته باشید که از شما بپرسد: “زمانی که این
ریفکتورینگ شما پایان می یابد آیا نرم افزار سریع تر اجرا میشود؟ آیا نرم افزار خطاهای کمتری خواهد داشت؟ طبیعتاً
جواب شما “خیر” است. چرا که انجام ریفکتورینگ بر روی کد دقیقاً همان خروجی را تولید خواهد کرد که نرم افزار از قبل
داشته است. اگر این جواب را به مدیر پروژه دهید شک ندارم که به شما خواهد گفت: “بنابراین ریفکتورینگ را کنار بگذار و
به کاری بپردازد که در روند پروژه مفید باشند.”

آخرین راه حل برای شکستن سیکل CRAP برنامه ریزی یا همان
Planning است. به عبارت دیگر معماری کردن نرم افزار برای طاقت آوردن در تغییراتی که در طی زمان اتفاق خواهد افتاد.
در چنین سناریویی فعالیت‌های Maintenance همانطور هندل می شوند که فعالیت‌های Development هندل می‌شوند. به عبارتی
دیگر هزینه زمانی و مالی یکسان بر روی طراحی و تجزیه تحلیل که در نرم افزار اولیه انجام می‌شد بر روی Maintenance
نیز انجام می‌ شود. دقیقاً شبیه اتفاقی که ممکن است برای ریفکتورینگ بیفتد ممکن است برای Planning نیز بیفتد. به
عبارتی کسی پیدا نشود که حاضر باشد هزینه های زمانی و مالی این روش را به عهده بگیرد. موضوع دیگر اینکه Planning
اغلب با شکست مواجه می‌شود چرا که ما نمی‌توانیم تغییراتی که در آینده بر روی نرم افزار به وجود خواهند آمد را به
طور کامل پیش بینی کنیم.

طبیعتاً این قضیه ما را به سمت برنامه نویسی چابک یا همان
Agile Development می رساند. بر اساس برنامه نویسی چابک ما برنامه ریزی های بلند مدت را کنار می‌گذاریم چرا که در
پیش‌ بینی آنها خوب نیستیم و تمرکز را بر روی چیزی می گذاریم که هم اکنون در حال انجام دادن آن هستیم. به عبارت دیگر
مدیریت طولانی مدت کنار گذاشته می‌شود و تمرکز بر روی مدیریت کوتاه مدت قرار میگیرد.

Domain Driven Design و شکست سیکل CRAP

بر اساس Domain Driven Design ما هیچ یک از تکنیک هایی که در جعبه ابزار
برنامه نویس هستند از قبیل ریفکتورینگ و برنامه نویسی بر اساس اصول SOLID و غیره را کنار نمی‌گذاریم. در واقع Domain
Driven Design به طور ساده می گوید که ما نباید اقدام به ساخت برنامه های بزرگ یا به عبارتی Big Ball of Mud یا گوله
ای بزرگ از گل و لای کنیم. بر اساس باور Domain Driven Design انسان‌ ها قادر به ساخت برنامه های بزرگ و پیچیده
نیستند اما قادرند که مسائل کوچک و به خوبی مرز بندی شده را بفهمند. واژه ای که برای این ماهیت در Domain Driven
Design از آن استفاده می شود Domain است. بر اساس Domain Driven Design ما Domain را با استفاده از واژه هایی که به
خوبی توسط افراد تیم توسعه نرم افزار و افراد تجاری یا همان Domain Expert ها فهمیده می شوند توصیف می‌کنیم. موضوع
دیگر اینکه Domain Driven Design این حقیقت را باور دارد که استفاده از یک واژه یکسان در قسمتهای مختلف یک سازمان یا
شرکت ممکن است معانی متفاوتی داشته باشد. برای مثال کلمه مشتری در دپارتمان بازاریابی یک معنی متفاوت با کلمه مشتری
در دپارتمان پشتیبانی دارد. در دپارتمان بازاریابی یک شرکت مشتری کسی است که در حال خرید کردن از ما است یا تصمیم به
خرید کردن از ما را دارد. اما در دپارتمان پشتیبانی مشتری کسی هست که قبلا از ما خرید کرده است و هم اکنون درخواست
دریافت پشتیبانی از ما را دارد. بر اساس اصول Domain Driven Design ما از ساخت نرم افزارهایی که تمامی یک سازمان را
Integrate و یا یکپارچه می‌کند و پوشش می دهد دست می کشیم چرا که این نرم افزار ها محکوم به شکست هستند. در عوض ما
به سمت نرم‌افزارهایی می‌رویم که کوچکتر هستند و فقط برای قسمت های جداگانه یک سازمان بزرگ نوشته شده اند. قسمت های
کوچکتری که در آن ها معنی کلمات همیشه ثابت هستند. به عبارت دیگر معنی کلمه Domain در Domain Driven Design قسمتی
است که کلماتی که در آن استفاده می شوند همگی یک معنی ثابت دارند.

اگر خاطرتان باشد گفتیم که در دپارتمان بازاریابی و دپارتمان
پشتیبانی معنی کلمه مشتری کاملاً متفاوت است. از همین جهت می‌توانیم نتیجه بگیریم که دپارتمان بازاریابی و دپارتمان
پشتیبانی Domain های متفاوت هستند. به منظور توصیف فعالیت‌های تجاری هر کدام از Domain ها از یک زبان مشترک به نام
Ubiquitous Language یا زبان فراگیر استفاده می‌شود. زبان فراگیر به این معنی نیست که یک زبان یکسان و تک در تمامی
قسمت های سازمان استفاده می شود. به عبارت دیگر این زبان مشترک فقط توسط افراد تیم توسعه و Domain Expert ها در
تمامی توصیف هایی که در رابطه با یک Domain انجام خواهد شد استفاده میشود. بنابراین Ubiquitous Language استفاده از
تمامی واژه های دیگر را لغو می‌کند و از یک زبان یکسان و مشترک و فراگیر و سراسری در تعریف فعالیت‌های تجاری یک
Domain استفاده می‌کند.

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

Comments

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *