اوانس در کتاب مشهور خود، چند الگو را برای دستیابی به Supple Design مورد تاکید قرار میدهد. هدف از این تاکیدات، دستیابی به نوعی از طراحی است که نهتنها کد خواناتر باشد، بلکه تغییرات آینده نیز با هزینه کمتری انجام شوند. یکی از آن الگوها، بستار عملیات (Closure of Operations) است.
بستار عملیات (Closure of Operations) چیست؟
بستار عملیات به طراحی عملیاتهایی اشاره دارد که خروجی آنها از همان نوع ورودیهایشان باشد یا در همان دامنه معنایی باقی بماند. به عبارت دیگر، وقتی عملیاتی را روی یک یا چند شیء از یک نوع خاص انجام میدهید، نتیجه باید بهگونهای باشد که همچنان در همان فضای مفهومی مدل دامنه قرار گیرد و نیازی به معرفی انواع جدید یا خروج از چارچوب دامنه نباشد.
برای مثال، فرض کنید در یک سیستم مالی با یک کلاس Money کار میکنید که نشاندهنده مقدار پول با یک ارز خاص است. اگر عملیاتی مانند جمع (add) تعریف کنید، این عملیات باید دو شیء Money را بگیرد و نتیجهاش نیز یک شیء Money باشد:
Money add(Money a, Money b) {
// اطمینان از یکسان بودن ارزها
return new Money(a.amount + b.amount, a.currency);
}
در اینجا، عملیات add بسته است، زیرا خروجی آن همچنان یک Money است و نیازی به ایجاد نوع جدیدی (مثلاً یک نوع عمومی یا یک ساختار متفاوت) نیست. این ویژگی باعث میشود که عملیاتها بهصورت طبیعی در زنجیرههای بزرگتر یا ترکیبهای پیچیدهتر استفاده شوند، بدون اینکه مدل دامنه را پیچیدهتر کنند.
چرا Closure of Operations مفید است؟
▫️حفظ یکپارچگی مدل دامنه:
با اطمینان از اینکه خروجی عملیاتها در همان فضای دامنه باقی میماند، مدل دامنه ساده و متمرکز باقی میماند. این کار از پراکندگی مفاهیم جلوگیری میکند و زبان همهجایی (Ubiquitous Language) را تقویت میکند، زیرا توسعهدهندگان و کارشناسان دامنه میتوانند بهطور مداوم با همان مفاهیم کار کنند.
▫️افزایش قابلیت ترکیبپذیری:
وقتی عملیاتها بسته هستند، میتوان آنها را بهراحتی با یکدیگر ترکیب کرد. برای مثال، در همان سیستم مالی، میتوانید عملیاتی مانند add و multiply را پشت سر هم استفاده کنید:
Money total = account1.balance.add(account2.balance).multiply(taxRate);
این ترکیبپذیری باعث میشود که کد خواناتر و قابلفهمتر باشد و منطق پیچیده دامنه بهصورت روان پیادهسازی شود.
🔹کاهش پیچیدگی و خطا:
وقتی خروجی عملیاتها از همان نوع ورودیهاست، نیاز به تبدیل انواع یا مدیریت موارد استثنایی کاهش مییابد. این کار احتمال خطاها را کم میکند و توسعهدهندگان را از نگرانیهای غیرضروری درباره ناسازگاری انواع آزاد میکند.
🔹تسهیل تستپذیری:
عملیاتهای بسته معمولاً پیشبینیپذیرتر هستند، زیرا خروجی آنها در همان دامنه ورودی باقی میماند. این ویژگی نوشتن تستهای واحد را سادهتر میکند، زیرا نیازی به بررسی انواع خروجی غیرمنتظره یا رفتارهای پیچیده نیست.
🔹انعطافپذیری در تغییرات:
در دامنههایی که نیاز به تغییرات مکرر دارند، عملیاتهای بسته به توسعهدهندگان اجازه میدهند بدون نیاز به بازطراحی ساختارهای پیچیده، منطق جدید را اضافه کنند. این انعطافپذیری بهویژه در سیستمهای در حال تکامل که دامنه آنها بهمرور پیچیدهتر میشود، ارزشمند است.
مثال عملی
فرض کنید در یک سیستم مدیریت موجودی انبار، کلاسی به نام Quantity دارید که نشاندهنده تعداد اقلام است. اگر عملیاتی مانند increase (افزایش موجودی) یا decrease (کاهش موجودی) تعریف کنید، این عملیاتها باید خروجیای از نوع Quantity تولید کنند:
Quantity increase(Quantity current, Quantity amount) {
return new Quantity(current.value + amount.value);
}
این طراحی تضمین میکند که هر عملیات روی Quantity همچنان در چارچوب مفهومی موجودی انبار باقی میماند. اگر خروجی این عملیات به نوع دیگری (مثلاً یک عدد خام یا یک نوع عمومی) تبدیل شود، توسعهدهندگان مجبور میشوند منطق اضافی برای مدیریت این ناسازگاری بنویسند، که هم پیچیدگی را افزایش میدهد و هم احتمال خطا را بالا میبرد.
نتیجهگیری
بستار عملیات با حفظ خروجی عملیاتها در همان دامنه ورودی، به سادهسازی مدل دامنه، افزایش ترکیبپذیری، کاهش خطاها و تسهیل نگهداری کمک میکند. این الگو به توسعهدهندگان اجازه میدهد کدی بنویسند که نهتنها با مفاهیم دامنه همراستاست، بلکه بهصورت طبیعی و روان در برابر تغییرات و نیازهای جدید پاسخگوست.
- انجمن DDD ایران
@DDD_IRAN
>>Click here to continue<<