آموزش اصول برنامه نویسی-شی دامنه
شی دامنه[۱]
آموزش برنامه نویسی اصولی
همانطور که پیشتر گفتم، برنامهنویسی شیگرا ابزاری است که ما از آن برای تحقق طراحی دامنه محور استفاده میکنیم. ما از قدرت کلاسها و کپسولهسازی استفاده زیادی خواهیم کرد. برای شروع تمرکز ما در این فصل روی اصول کلاسها و بعضی تکنیکهای مرتبط خواهد بود، چیزی که بسیاری از برنامهنویسان همین الان هم به آن مسلط هستند. فعلاً سراغ مبحث ذخیرهسازی (تعامل با پایگاه داده) نخواهیم رفت. اگر اولین باری است که با این نوع طراحی کار میکنید ممکن است مدام به فکر پایگاه دادهها[۲] و دسترسی به آن بیافتید. فعلاً به آن خیلی فکر نکنید. در فصل بعدی اصول ذخیرهسازی را بررسی خواهیم کرد. حتی در فصول بعدتر نگاه عمیقتری به این مسأله خواهیم داشت.
ایده پشت طراحی دامنه محور ساخت سیستم به نحوی است که منعکس کننده دامنه مسئلهای باشد که در حال حل آن هستید. اینجا همان جایی است که کار خبرگان دامنه شروع میشود. آنها به شما کمک میکنند تا روش کار سیستم را بفهمید (حتی اگر صرفاً از طریق راهنمای کاغذی باشد) و بدانید که چطور کار میکند. اول کار ممکن است با دیدن مهارت و اطلاعات آنها احساس حقارت کنید. آنها درباره چیزهایی حرف میزنند که شما هرگز چیزی از آنها نشنیدهاید و از دیدن نگاههای گیج و مبهوت شما احساس تعجب خواهند کرد. آنها از لغات و اصطلاحاتی استفاده خواهند کرد که شما مدام راجع به آن خواهید پرسید. نهایتاً هدف یک برنامهنویس فهم و درک همین دامنه مسأله است. شما به طور عمومی میتوانید برنامهنویسی کنید اما میتوانید یک سیستم انبار خاص را هم برنامهنویسی کنید؟ یا ما باید کار خبرگان دامنه را یاد بگیریم یا آنها کار ما را. مسلماً اگر قرار باشد آنها برنامهنویسی را یاد بگیرند آن وقت همه ما برنامهنویسها از کار بیکار خواهیم شد.
هر کسی که در کار نرمافزار بوده میداند که یادگیری منطق یک کسب و کار[۳] جدید پیچیدهترین قسمت کار برنامهنویسی است. به همین دلیل هر چه قدر که بتوانیم کد برنامهها را بیشتر شبیه به کسب و کار کنیم بهتر است. برقراری ارتباط مهمترین چیزی است که مد نظر من است. اگر کاربران در مورد برامدهای استراتژیک (Strategic Outcomes) حرف میزنند، چیزی که یک ماه پیش هیچ معنی برای شما نداشت، و کد شما چیزی به اسم StrategicOutcomes داشته باشد آن وقت خیلی از ابهامات و اشتباهات از بین خواهد رفت. خیلی از مردم از جمله خود من معتقد هستند که بهترین نقطه شروع، استفاده از اسمهایی است که خبرگان یک کسب و کار و کاربران از آن استفاده میکنند. مثلاً اگر در حال ساخت سیستمی برای یک فروشگاه ماشین هستید و با فروشنده (که احتمالاً هم یک کاربر است و هم یک خبره دامنه) صحبت میکنید، بدون شک او از کلماتی مثل مشتری (Client)، ماشین (Car)، مدل (Model)، بسته (Package)، ارتقا (Upgrade)، پرداخت (Payment) و… استفاده خواهند کرد. همانطور که که این چیزها هسته اصلی کسب و کار او را تشکیل میدهند، منطقی است که هسته سیستم شما را هم تشکیل دهند. پشت سر این اسمها، همگرایی زبان کسب و کار وجود دارد که به زبان ماندگار یا همه جا حاضر[۴] معروف است. ایده این است که زبان مشترک بین کاربران و سیستم قابلیت نگهداری بیشتری داشته و احتمال برداشت اشتباه کمتری از آن وجود دارد.
چگونگی شروع کار به خود شما بستگی دارد. طراحی دامنهمحور لزوماً به این معنی نیست که شما باید با مدلسازی دامنه مسئله شروع کنید (هر چند که ایده خوبی است!)، بلکه به این معنی است که شما باید روی دامنه مسئله تمرکز کرده و اجازه دهید تصمیمگیریهایتان را هدایت کند. اول کار میتوان با مدل دادهها شروع کرد. البته وقتی که به مدل آزمون محور برسیم از روش دیگری استفاده خواهیم کرد. فعلاً فرض کنید که با مشتری و تعدادی از فروشندههای آنها صحبت کردهایم و فهمیدهایم که یکی از نکات مهم و اصلی کار انها نگهداری اطلاعات وابستگیهای بین گزینههای ارتقای مدل ماشینها است. اولین کاری که انجام میدهیم ساخت ۴ کلاس است:
public class Car{}
public class Model{}
public class Package{}
public class Upgrade{}
قدم بعدی اضافه کردن مقداری کد است که معمولاً به همه جا اضافه میشوند:
public class Car
{
private Model _model;
private List<Upgrade> _upgrades;
public void Add(Upgrade upgrade){ //todo }
}
public class Model
{
private int _id;
private int _year;
private string _name;
public ReadOnlyCollection<Upgrade> GetAvailableUpgrades()
{
return null; //todo
}
}
public class Upgrade
{
private int _id;
private string _name;
public ReadOnlyCollection<Upgrade> RequiredUpgrades
{
get { return null; //todo }
}
}
همه چیز خیلی ساده است. ما چند فیلد سنتی (id, name)، چند رابطه (Cars و Models هر دو Upgrade دارند) و یک متد به اسم Add را به کلاس Car اضافه کردیم. حالا میتوانیم کمی آن را تغییر داده و رفتار واقعی را به آن اضافه کنیم:
{
private Model _model;
//todo where to initialize this?
private List<Upgrade> _upgrades;
public void Add(Upgrade upgrade)
{
_upgrades.Add(upgrade);
}
public ReadOnlyCollection<Upgrade> MissingUpgradeDependencies()
{
List<Upgrade> missingUpgrades = new List<Upgrade>();
foreach (Upgrade upgrade in _upgrades)
{
foreach (Upgrade dependentUpgrade in upgrade.RequiredUpgrades)
{
if (!_upgrades.Contains(dependentUpgrade)
&& !missingUpgrades.Contains(dependentUpgrade))
{
missingUpgrades.Add(dependentUpgrade);
}
}
}
return missingUpgrades.AsReadOnly();
[dropcap][/dropcap][highlight][/highlight] }
}
اول اینکه متد Add را پیادهسازی کردیم. دوم اینکه متدی ساختیم که به ما اجازه میدهد تا تمام «ارتقا»های ناموجود را پیدا کنیم. این فقط یک گام ابتدایی است. قدم بعدی میتواند پیدا کردن ارتقاهایی باشد که مسئول ارتقاهای ناموجود هستند. مثلاً شما باید یک ماشین با محور ۴ چرخ (۴ Wheel Drive) را انتخاب کنید تا بتوانید از سیستم کنترل اصطکاک (Traction Control) استفاده کنید. همینجا دست نگه میداریم. هدف تنها نشاندادن آن بود که چگونه میتوانیم شروع کنیم و اصلاً شروع کار چه شکلی است.
[۱] Domain Object
[۲] Database
[۳] Business
[۴] Ubiquitous