رویدادهای دامنه؛ وقتی هر واکنش کار خودشو میکنه
خلاصهٔ کاملتر
نویسنده میگه بیشتر منطق کسبوکار به این شکل خلاصه میشه: «وقتی یه چیزی اتفاق میافته، یه چیز دیگه باید بشه». مشکل اینه که وقتی ثبت سفارش رو با ارسال ایمیل، خبر دادن به انبار و آپدیت آنالیتیکس تو یه اسکریپت قاطی میکنی، فکت اصلی (اینکه سفارش ثبت شد) گم میشه و باید همهجا تکرارش کنی. تازه اگه ایمیل یا انبار خطا بده، معلوم نیست کل عملیات موفق بوده یا نه.
به گفتهٔ نویسنده، رویداد دامنه (domain event) یه فکت رو با زبون خود کسبوکار ثبت میکنه، نه یه دستور کار. برای همین اسمش گذشتهست: OrderPlaced یعنی سفارش ثبت شده، نه «ایمیل بفرست». رویداد باید تغییرناپذیر باشه و فقط اونقدر داده داشته باشه که فکت قابل فهم باشه. این فرقِ رویداد با کامند (command) هم هست: کامند یه نیت رو میرسونه و میشه ردش کرد، ولی رویداد نتیجهی یه تصمیم گرفتهشده رو ثبت میکنه.
نویسنده میگه رویداد رو باید همونجا ثبت کنی که تصمیم واقعی گرفته میشه، یعنی داخل aggregate یا عملیات دامنهای که قانونها رو چک میکنه. بعد هر واکنش میره تو یه handler جدا که فقط یه مسئولیت داره و از بقیه بیخبره:
class SendConfirmationEmail:
handle(OrderPlaced event):
email = buildConfirmation(event.orderId)
mailer.send(email)اینطوری اون لیست کارهای بههمچسبیده تبدیل میشه به چند تا اکشن مستقل که هر کدوم خطا و retry خودشو دارن. خود aggregate رویدادها رو جمع میکنه ولی هیچوقت خودش پخششون نمیکنه؛ این کار رو زیرساخت (مثلاً unit of work بعد از commit) انجام میده.
نویسنده هشدار میده که همهچی رو رویداد نکن. رویداد وقتی میارزه که یه فکت معنادار باشه و یکی بخواد بهش واکنش نشون بده؛ ساختن رویداد برای هر setter فقط شلوغی میسازه. وقتی هم از مرز یه bounded context رد میشی، باید رویداد داخلی رو به یه integration event ترجمه کنی که context مقصد بفهمتش، و برای تحویل مطمئن معمولاً باید سراغ الگوی transactional outbox بری.
نکات کلیدی:
- رویداد دامنه یه فکت گذشته و تغییرناپذیره، نه یه دستور کار
- فکت رو همونجا که تصمیم گرفته میشه (داخل aggregate) ثبت کن
- هر واکنش تو یه handler مستقل با خطا و retry مخصوص خودش
- همهی تغییرها رویداد نیستن؛ برای مرز context از integration event و outbox استفاده کن




