TGViewer
C# Geeks (.NET) C# Geeks (.NET) @csharpgeeks · 550 subscribers
Post #644 348
public Result Publish(IDateTimeProvider clock)
{
if (Status != CourseStatus.Draft)
{
return CourseErrors.AlreadyPublished;
}

if (_lessons.Count == 0)
{
return CourseErrors.CannotPublishWithoutLessons;
}

Status = CourseStatus.Published;
PublishedOn = clock.UtcNow;

return Result.Success();
}

در این طراحی: Handler دیگر مسئول دانستن قوانین نیست.
فقط متد Publish را فراخوانی می‌کند.
خود Entity تصمیم می‌گیرد آیا عملیات مجاز است یا خیر.
3️⃣ محافظت از Aggregate

برخی قوانین تنها به یک Entity محدود نیستند و چندین Entity درون یک Aggregate را درگیر می‌کنند.
در چنین شرایطی Aggregate Root مسئول حفظ Invariantها است.
مثال: Course منتشرشده باید حداقل یک Lesson داشته باشد.
پس از انتشار Course، حذف Lessonها مجاز نیست.
پیاده‌سازی صحیح:
public sealed class Course
{
private readonly List<Lesson> _lessons = [];

public IReadOnlyCollection<Lesson> Lessons =>
_lessons.AsReadOnly();

public Result RemoveLesson(LessonId id)
{
if (Status == CourseStatus.Published)
{
return CourseErrors
.CannotModifyPublishedLessons;
}

var lesson =
_lessons.FirstOrDefault(l => l.Id == id);

if (lesson is null)
{
return CourseErrors.LessonNotFound;
}

_lessons.Remove(lesson);

return Result.Success();
}
}

در این مدل:
هیچ مصرف‌کننده‌ای نمی‌تواند مستقیماً Collection را تغییر دهد.
تمام تغییرات باید از طریق Aggregate Root انجام شوند.
در نتیجه Invariantها همیشه حفظ خواهند شد.
🎯 اگر قانون بین چند Aggregate باشد چه؟

اینجا دیگر مسئولیت یک Aggregate تمام می‌شود.
اگر قانونی بین دو Aggregate مستقل وجود داشته باشد، معمولاً باید از Domain Event استفاده شود.
نه اینکه یک Aggregate مستقیماً وارد Aggregate دیگر شود.
این دقیقاً یکی از دلایل اصلی وجود Domain Eventها در DDD است.
🚀 نتیجه واقعی این رویکرد چیست؟
شاید همان سیستم را بتوان به‌صورت Procedural نیز پیاده‌سازی کرد.
اما چیزی که به دست می‌آورید «اعتماد» است.
در یک سیستم Procedural:
تمام مصرف‌کنندگان مسئول حفظ قوانین هستند.
اما در یک Always Valid Model:
مسئولیت حفظ قوانین فقط بر عهده Domain Model است.
این تفاوت در طول زمان تأثیر بزرگی ایجاد می‌کند:
✅ ءValidationها از هم فاصله نمی‌گیرند.
✅ قوانین تکرار نمی‌شوند.
✅ ءEndpointهای جدید نمی‌توانند به‌اشتباه قوانین را دور بزنند.
✅ تست‌ها ساده‌تر می‌شوند.
✅ ءDomain Model به مرکز واقعی قوانین کسب‌وکار تبدیل می‌شود.
📌 جمع‌بندی

ءInvariant قانونی است که باید در تمام طول عمر یک Object برقرار باشد.
بهترین محل برای اعمال این قوانین خود Domain Model است.
ءInvariantهای مربوط به ساخت Object در Factory و Constructor خصوصی قرار می‌گیرند.
ءInvariantهای مربوط به تغییر وضعیت در متدهای Domain پیاده‌سازی می‌شوند.
ءInvariantهای سطح Aggregate توسط Aggregate Root محافظت می‌شوند.
در مقابل، ممکن است مقداری از سادگی ظاهری کدهای Procedural را از دست بدهید.
اما در عوض مدلی خواهید داشت که همیشه معتبر است و می‌توانید به آن اعتماد کنید.
و این دقیقاً یکی از مهم‌ترین اهداف Domain-Driven Design است.
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 →