معماری Domain Event کامل + مثال - قسمت اول

سلام دوستان - تو این مقاله نسبتا طولانی قراره یکم راجع به معماری Domain Event صحبت کنیم اینکه چی هست - کجا به کارمون میاد - چه ارتباطی با DDD و Event Sourcing داره - چطور پیاده سازیش کنیم اصلا ! و چه چالش هایی رو واسمون حل میکنه DDDچیست ؟معماری Domain Driven Design یک معماری بسیار مستحکم و قدرمند نرم افزاری می باشد که برای پروژه هایی با پیچیدگی های فراوان طراحی شده است. در این معماری پایین ترین لایه دیتابیس یا داده نمی باشد. بلکه پایین ترین لایه منطق های اصلی پروژه می باشد.به عنوان مثال فرض کنید قرار است یک بازی شطرنج را پیاده سازی کنید. در این بازی هر مهره چندین حرکت می تواند انجام دهد و از قواعد خاصی نیز پیروی می شود. ترکیب حرکت مهره ها میلیون ها حرکت را به وجود می آورد. قطعا پیاده سازی میلیون ها حرکت تست کد غیر ممکن است. بنابراین در اینجا بایستی هر مهره را به عنوان یک Value Object تعریف کرد و رفتار آن را مشخص کرد.مثال دیگری که می توان برای استفاده از معماری DDD گفت پیاده سازی سیستم های پیش بینی آب و هوا می باشد. در این سیستم ها برای پیش بینی هوا هزاران عامل وجود دارد که هر عامل میتواند بر عامل یا عوامل دیگر تاثیر گذار باشد. بنابراین برای پیاده سازی چنین سیستم هایی معمولا از معماری DDD استفاده می شود. 1مشکل: بزارید اول مشکل رو بگم و بعد بریم سراغ مابقی ماجرا :فرض کنید شما یک سامانه فروشگاه آنلاین دارید که از میکروسرویس های مختلفی تشکیل شدهیکی از این میکروسرویس ها مسئول مدیریت سفارشات هست و یکی دیگه مسئول مدیریت انبار-حالا فرض میگیریم کاربر سفارش جدیدی ثبت میشه تو حالت عادی وضعیت سفارش باید به ثبت شده تغییر پیدا کنه اطلاعات خریدار و روش پرداخت بررسی یا اضافه کنیم موجودی کالای سفارش داده شده از میکروسرویس انبار بگیریم و کم کنیمفاکتور سفارش صادر و به خریدار ارسال کنیمحال فرض کنیم تمامی موارد بالا با استفاده از درخواست های همزمان (synchorouns )بخواد انجام بشه - تو این حالت باید با استفاده از Api های Restfull یا GRPC درخواست مستقیم به سایر میکروسرویس ها بزنیم و منتظر پاسخشون بمونیم این کار یکسری مشکل داره coupling بالا :میکروسرویس سفارشات باید دقیقا بدونه با چه API های دیگه ای ارتباط برقرار کنه و میکروسرویس چه پارامتر هایی ارسال و چه پاسخ هایی دریافت کند این باعث محدود شدن مواردی مثل flexibilty - scabilty - maintaibilty میشه خطای بالا :میکروسرویس سفارشات وابسته به درست کار کردن مابقی میکروسرویس هاست و اگر یک میکروسرویس خطا داشته باشد یا قطع شود عملیات سفارش ناتموم و معلوم نیست چه اتفاقاتی دقیقا رخ داده این اتفاق باعث inconsistency و دشواری rollback در صورت خطای سامانه میشود عملکرد پایین: میکروسرویس سفارشات باید منتظر پاسخ سایر میکروسرویس ها باشه تا عملیات تکمیل بشه این کار باعث کندشدن پاسخگویی به درخواست های کاربر و ضعف تجربه کاربری هست حالا فرض میگیریم این کار رو با رویداددامنه انجام میدیم....1- میکروسرویس سفارشات پس از ثبت سفارش یک رویداد دامنه تولید(OrderStartedDomainEvent) و منتشر میکند2- میکروسرویس خریداران با استفاده از یک Domain Event Handler ( تو فصل طراحی توضیح میدم) عضو میشوند و پس از دریافت خودکار این رویداد چک میکنند عملیات ثبت سفارش موفق بوده یا خیر 3- میکروسرویس انبار هم با استفاده از یک Domain Event Handler به اسم updateStockWhenOrderStartedDomain() به این ایونت هندلر عضو میشوند و پس از دریافت آن خودکار موجودی کالا را کاهش میدن4- همینطور میکروسرویس فاکتور و همین اتفاقات - دریافت رویداد - ایجاد فاکتور و ارسال ... مزایا : عملکرد بالا : میکروسرویس سفارشات نیازی ندارد که منتظر پاسخ سایر میکروسرویس ها باشد تا عملیات را تکمیل کند هر میکروسرویس بصورت غیرهمزمان (asynchoronus ) و مستقل Domain Event های خود را پردازش میکند - این باعث افزایش سرعت پاسخگویی به درخواست های کاربران و بهبود تجربه کاربری میشودخطای پایین : میکروسرویس سفارشات وابسته به درست کار کردن میکروسرویس های دیگر نیست اگر یک میکروسرویس قطع یا خطا داشته باشد عملیات سفارش قطع نمیشود و تاثیری ندارد روی آن - این باعث کاهش ناسازگاری (inconsistency ) و اسانتر شدن عملیات رول بک میشودخب Domain Event (رویداد دامنه )چیست ؟طبق تعریف مایکروسافت رویداد چیزی هست که تو گذشته اتفاق افتاده و رویداد دامنه اتفاقی هست که تو یک دامنه افتاده و میخوایم سایر بخش های در حال پردازش همون دامنه بهش اطلاع بدیم ! دامنه : "حوزه دانش یا فعالیت". با کمی عمیق شدن، دامنه در حوزه مهندسی نرم افزار معمولاً به موضوع و هدفی که برنامه ی نرم افزاری در آن اعمال می شود، اشاره داردطبق تعریف مارتین فولر بزرگ ! Captures the memory of something interesting which affects the domainما هرچیزی که فکر میکنیم با دامنه سروکار داره رو باید ثبت کنیم (مثال معروف GIGO)- ماهیت یک رویداد دامنه هم همین هست که از آن برای ثبت مواردی استفاده می‌کنیم که باعث تغییر در وضعیت برنامه‌ای که در حال توسعه آن هستیم بشود.رویداد های دامنه رو نباید با integration Event ها اشتباه گرفت - integration Event ها زمانی استفاده میشوند که شما نیاز دارید یک رویداد رو بصورت غیرهمزمان و خارج از پردازش فعلیتون منتشر کنیدبرای مثال بین چندتا microservice , Bounded Context یا حتی برنامه های مختلفویژگی های Domain Event :آنها Immutable و یا غیر قابل تغییر هستند. دلیل این موضوع هم منطقی است چرا که اتفاقی که افتاده است را نمیتوان تغییر داد.دارای یک Time Stamp هستند که مشخص کننده زمان رخ دادن Domain Event مورد نظر است.میتوانند دارای یک ID منحصر به فرد باشند که با استفاده از آن بتوانیم یک Event را از یک Event دیگر تمیز بدهیم. این موضع بستگی به نوع Domain Event و همچنین نحوه توزیع شدن Event ها دارد.توسط Aggregate Root ها و یا Domain Service ها منتشر و یا Publish میشوند. در رابطه با این موضوع بعدا بیشتر صحبت میکنیم. مزایا : بنظرم بزرگترین وبهترین مزایایی که داره قابل گسترش بدون سیستم هست شما میتونید n تا Business Logic مختلف رو با فقط با اضافه کردن Domain Event Listener بیشتر بدون تغییر در داخل کد های از قبل موجود انجام بدیم - گسترش کد بدون تغییر کد های قبل یکی از اصول Solid بود( Open Close Principle) شاید با خودتون بگید خب چه کاریه اصلا ! همون اول هرچی ایونت و بیزینسی که مدیر دامنه بهمون میگه رو داخل کد تزریق میکنیم اما ممکنه اصل Yagni که مخفف You aren't gonna need it را زیر پا بگذارید. روش بهتر اینه است که برنامه باز باشه تا بتونیم به راحتی در صورت لزوم Domain Event های جدید را اضافه و سپس انتشار بدیمبخش های مختلف سیستم رو میتونیم جدا کنیم وابستگی و اتصالات مستقیم رو کاهش بدیم و سیستم قابل توسعه تری داشته باشیم قوانین تجاری دامنه رو جدا از خود دامنه و بدون اسیب زدن بهش میتونیم تغییر بدیمبه زبون ساده تر فرض کنید یک سایت فروشگاهی داریم و هرکدوم از فعالیت هایی که مستقل از هم هستند رو میتونیم دامنه در نظر بگیریم - دامنه کاربران - دامنه سفارشات - دامنه خرید - دامنه ارسال و .. شکل بالا بهتون نشون میده که چطوری میشه consistency رو بین چند مجموعه تو یک دامنه بدست آورد هرزمان که سفارش جدید کاربر ثبت بشه مجموعه Order Aggregate یک رویداد OrderStarted رو منتشر میکنه و متناوبا میتونیم بقیه رویداد ها رو هم کنترل کنیم مثال اگر تعداد کالای درخواستی زیاد بود رویداد مجزا تولید کنیمچه زمانی استفاده کنیم ؟هر زمانی که سامانه ای که در حال پیاده سازیش هستید یک سامانه توزیع شده با coupling پایین هست که نیاز به ارتباط و تبادل داده بین بخش های مختلف رو داره سامانه نیاز به پردازش رویداد های غیرهمزمان با سرعت بالا رو داره سامانه با نیازبه بروزرسانی قوانین دامنه به صورت صریح و مبتنی بر زبان رایج کسب کار هستیمو نیاز داریم به اثرات جانبی تغییرات در دامنه اهمیت زیادی بدیم و واضح پیاده سازی کنیمگزارش کاملی از عملکرد سیستم بخوایمتو قسمت های بعدی میریم برای پیاده سازی یک نمونه نسبتا ساده - به همراه تست و نتیجه ! سعی کردم خلاصه و قابل فهم باشه - اگر مشکل یا ایرادی بود عذرخواهی میکنم ازتون و قسمت های بعدی اصلاح میشه - لطفا نظرتون رو حتما بگید خوشحال میشم منابع : https://medium.com/@mena.meseha/use-domain-events-in-microservices-fb99a16ed590 https://learn.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/domain-events-design-implementation https://www.martinfowler.com/eaaDev/DomainEvent.html