در این پست از وبسایت پرووید میخواهیم در رابطه با 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 را چگونه بشکنیم یک موضوع بسیار مهم در روند تکامل نرم افزار و استراتژیهای طراحی آن است. ما پیش از این در رابطه با نرم افزارهای 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 ما هیچ یک از تکنیک هایی که در جعبه ابزار برنامه نویس هستند از قبیل ریفکتورینگ و برنامه نویسی بر اساس اصول 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 دیگر ارتباطی برقرار کنید. برای چنین شرایطی از معماری ها سرویس گرا می شود استفاده کرد.
منبع: وبسایت پرووید