TGViewer
C# Geeks (.NET) C# Geeks (.NET) @csharpgeeks · 550 subscribers
Post #643 225
🎯 ءInvariant چیست و چرا بهترین مکان برای اعمال آن Domain Model است؟

بخش زیادی از کدهای به‌ظاهر DDD که در پروژه‌های NET. می‌بینم، قوانین کسب‌وکار را بین Handlerها، Validatorها و Controllerها پخش کرده‌اند، اما خود Domain Model تقریباً هیچ نقشی در محافظت از این قوانین ندارد.نتیجه چیست؟
همان قانون در چندین نقطه مختلف تکرار می‌شود، هر نسخه به مرور کمی از نسخه‌های دیگر فاصله می‌گیرد و در نهایت معتبر بودن یک شیء به این بستگی پیدا می‌کند که از چه مسیری وارد سیستم شده است.
البته می‌توان با این رویکرد سیستم‌های کاملاً عملیاتی ساخت. همه ما پروژه‌هایی را دیده‌ایم که با تعداد زیادی if و Validation کار می‌کنند و سال‌ها بدون مشکل در حال اجرا هستند.
اما راه بهتری هم وجود دارد؛ راهی که از یک مفهوم بسیار مهم شروع می‌شود: Invariant
💡 ءInvariant چیست؟

ءInvariant قانونی است که باید در تمام طول عمر یک شیء برقرار بماند.
نه فقط هنگام ذخیره شدن در پایگاه داده.
نه فقط زمانی که یک Validator اجرا می‌شود.
بلکه هر زمان که به آن شیء دسترسی پیدا می‌کنید، باید آن قانون برقرار باشد؛ فارغ از اینکه شیء چگونه ساخته شده یا از کجا بارگذاری شده است.
چند مثال:
✅ یک Course همیشه باید عنوان داشته باشد.
✅ مجموع Order همیشه باید برابر مجموع آیتم‌های آن باشد.
✅ یک Subscription در هر لحظه فقط در یکی از وضعیت‌های Trial، Active، PastDue یا Canceled قرار دارد.
✅ یک Course منتشرشده باید حداقل یک Lesson داشته باشد.
نکته مهم اینجاست که هیچ‌کدام از این قوانین درباره HTTP، Validation یا Database صحبت نمی‌کنند.
این‌ها قوانین دامنه هستند و باید مستقل از زیرساخت همیشه برقرار باشند.
❌ مشکل رویکردهای Procedural

فرض کنید یک Course به شکل زیر تعریف شده باشد:
public class Course
{
public string Title { get; set; }
public CourseStatus Status { get; set; }
public DateTime? PublishedOn { get; set; }
public decimal Price { get; set; }
}

در این طراحی: Constructor وجود ندارد.
تمام Setterها عمومی هستند.
هر کسی می‌تواند هر مقداری را در هر زمانی تغییر دهد.
در نتیجه قوانین کسب‌وکار در بخش‌های مختلف سیستم پخش می‌شوند:
ءCreateCourseValidator بررسی می‌کند Title خالی نباشد.
ءPublishCourseHandler بررسی می‌کند Course قبلاً منتشر نشده باشد.
ءChangePriceHandler بررسی می‌کند Course آرشیو نشده باشد.
ءEndpoint جدیدی اضافه می‌شود و توسعه‌دهنده یکی از Handlerهای قبلی را Copy می‌کند اما یکی از Validationها را فراموش می‌کند.
اینجاست که مدل به‌تدریج وارد وضعیت‌های نامعتبر می‌شود.
مشکل اصلی Anemic Model همین است.
نه اینکه رفتار ندارد.
بلکه هیچ تضمینی درباره وضعیت خودش ارائه نمی‌کند.
در نتیجه تمام مصرف‌کنندگان آن مجبورند دائماً قوانین را تکرار کنند.
✅ Always Valid Model

ایده اصلی بسیار ساده است:
ءDomain Model نباید هیچ‌گاه وضعیت نامعتبر را بپذیرد.
اگر Reference یک Course را در اختیار دارید، باید بتوانید به آن اعتماد کنید.
نباید در لایه‌های بالاتر دائماً بنویسید:
if(course.Title is null)

نباید چندین Validator موازی داشته باشید.
نباید امیدوار باشید که Handler مربوطه Validationها را فراموش نکرده باشد.
برای رسیدن به این هدف معمولاً سه اصل مهم وجود دارد.
1️⃣ جلوگیری از ساخت Object نامعتبر

اگر Course بدون Title معنایی ندارد، پس نباید امکان ساخت آن وجود داشته باشد.
public class Course
{
private Course(CourseId id, string title, Money price)
{
Id = id;
Title = title;
Price = price;
Status = CourseStatus.Draft;
}

public static Result<Course> Create(string title, Money price)
{
if (string.IsNullOrWhiteSpace(title))
{
return CourseErrors.TitleRequired;
}

return new Course(CourseId.New(), title, price);
}
}

در اینجا: Constructor خصوصی است.
تمام ساخت Object از طریق Factory انجام می‌شود.Validation تنها در یک نقطه انجام می‌شود.
از این لحظه به بعد هر Course موجود در سیستم دارای Title معتبر است.
2️⃣ محافظت از تغییر وضعیت‌ها

حتی اگر ساخت Object کنترل شود، همچنان تغییر وضعیت می‌تواند قوانین را نقض کند.
به همین دلیل Setterهای عمومی نباید وجود داشته باشند.
تمام تغییرات باید از طریق متدهایی انجام شوند که قوانین را می‌شناسند.
More from @csharpgeeks
  1. Sep 22, 2026یه مدتی قراره از دنیای NET. فاصله بگیرم، چون وقتشه برم سربازی. راستش نمیدونم این مدت رو چج…
  2. Sep 20, 2026🔥 حالا مشکل اصلی: Alert Storm فرض کن Database از دسترس خارج شده. ۱۰۰ Pod داری. هر Pod می‌…
  3. Sep 20, 2026🚨 طراحی سیستم Monitoring و Alerting در یک سیستم بزرگ فرض کن ساعت ۳ صبح است. سیستم شما با…
  4. Sep 19, 2026#Engineering_Leadership تصمیم نگرفتن هم یک تصمیم است یه چیز عجیب توی تیم‌های مهندسی: گاهی…
  5. Sep 19, 2026☑ چک‌لیست آماده‌سازی تیم، فرایندها و زیرساخت برای توسعه با AI توجه: هیچ چک‌لیستی جهان‌شمول…
  6. Sep 19, 2026📌پایان یک انتظار طولانی: اعتبارسنجی ناهمگام (Async Validation) در NET 11.
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →