Event Sourcing بخش چهارم
Event Sourcing بخش سوم
لیست مطالب آموزشی Event Sourcing:
- بخش اول مقدمهای بر Event Sourcing
- بخش دوم آشنایی مقدماتی با ساختار داخلی Event Store
- مقایسه رویکردهای State-Oriented و State-Transition
- مزیتهای Event Sourcing
- سلام به دنیا به روش Event Sourcing
- سلام به دنیا به روش Event Sourcing-بخش دوم
- بخش هفتم Projection
- بخش هشتم ویرایش ایونت ها در EventSourcing
- بخش نهم Message، Command یا Event
مزیتهای Event-Sourcing
در پست قبلی در مورد رویکردهای State-Oriented و State-Transition صحبت کردم. در این پست در مورد مزیتهای Event Sourcing که یکی از مهمترین نمودهای عینی رویکردهای مبتنی بر State-Transition ها است صحبت خواهم کرد. برخی از دومین هایی که بصورت روزانه با آنها سرو کله میزنیم، ذاتا ایونت سورس میباشند. شناخت مزیتهایی که طراحی یک سیستم بصورت Event Sourced به ما میدهد میتواند بسیار مفید باشد. جهت شناخت برخی از مهمترین مزیتها این مقاله را دنبال کنید.
-
مقدمه
در Event Sourcing ما تمامی تغییراتی که درstate برنامه رخ داده است را در قالب دنبالهای از Event ها ذخیره میکنیم. در واقع ایدهی ساده در اینجا این است که مطمئن بشویم هیچ تغییر state ای در برنامه را از دست نمیدهیم و تمامی تغییرات صرفنظر از بزرگی یا کوچکی و نوع تغییر در یک فایل audit که بصورت سری زمانی است ذخیره خواهد شد. با اینکار نه تنها در هر لحظه میتوانیم آخرین state برنامه را داشته باشیم، بلکه میتوانیم مسیری که هر resource در برنامه طی کرده است را نیز داشته باشیم.
در حقیقت یک Event تغییراتی که در یک لحظه خاص در برنامه رخ داده را در خود، رکورد میکند. در نهایت این Event به درون فایل لاگ ذخیره میشود. همانطور که میتوان مشاهده کرد، با اینکار ما نه تنها تغییرات داده در آن لحظه از زمان را داریم، بلکه دلیل تغییر بوجود آمده را نیز خواهیم داشت. State Transition در حقیقت Eventهایی هستند که آن چیزی که در state برنامه شما تغییر کرده است، را ثبت کرده و در فایل لاگ-به عنوان دیتابیس، ذخیره میکند. این باعث میشود که یک لاگ غیر قابل تغییر! و دائمی از تمامی تغییرات state برنامه بصورت کامل داشته باشیم.
اولین مزیتی که در این طراحی میتوانیم به آن اشاره کنیم، این است که ما یک لاگ از تمامی تغییرات برنامه به ترتیب زمان وقوعشان داریم.
The key to Event Sourcing is that we guarantee that all changes to the domain objects are initiated by the event objects.
Martin Fowler
خب اجازه بدهید به این سوال پاسخ دهیم که طراحی سیستم بصورت Event Sourced چه مزیتهایی میتواند برای ما به همراه داشته باشد.
-
مزیتهای Event Source کردن سیستم
- تاریخچه اینکه به چه صورت یک انتیتی به وضعیت فعلی رسیده است را بصورت کامل نگه میداریم. در نتیجه با داشتن این تاریخچه استدلال کردن -reasoning بسیار سادهتر و کارآمدتر خواهد شد.
به عنوان مثال میخواهیم ببینیم چرا بالانس حساب بانکی ۵۰۰ دلار میباشد. میتوانیم به راحتی با دنبال کردن دنبالهی eventهای رخداده بر روی این حساب بانکی در Event Store جواب این سوال را براحتی پیدا کنیم.
همانطور که مشاهده میکنید استدلال کردن در این روش بسیار راحت است. میتوانیم با دنبال کردن، state transition های مختلف برنامه براحتی استدلال کرد یا استدلال خود را اثبات کرد.
- با داشتن تاریخچه کامل از تمامی تغییرات اتفاق افتاده بر روی هر انتیتی و چگونگی حرکت کردن انتیتی بین این وضعیتها، میتوان اطلاعات کسبوکاری مهمی را استخراج کرد. از این اطلاعات میتواند دلایل برای تحلیلهای بیزنسی بعدی نیز استفاده کرد.
به عنوان مثال با بررسی استریمهای زیر که مربوط به سفارشات کاربران است، مشاهده میکنیم که یک الگوی رفتاری در انتخاب و خرید گوشی تلفن همراه برای کاربران وجود دارد.
همانطور که میتوانیم مشاهده کنیم کاربران ابتدا ترغیب به خرید گوشی آیفون شدهاند، اما پس از آن به دلایلی ترجیح دادهاند که سامسونگ را انتخاب کنند. این میتواند به ما یک بینش-insight مهم در رفتار خرید کاربران به ما بدهد.(ترتیب قرار گرفتن ایونتهای افزودن آیفون-افزودن سامسونگ-حذف آیفون از سبد خرید، فقط برای سادگی مثال است. و ترتیب آنها اصلا مهم نیست. ممکن است کاربر ابتدا گوشی آیفون را به سفارش اضافه کند، و سپس در آخرین لحظه آن را از سبد خود حذف کند، و سپس گوشی سامسونگ را ب سبد اضافه کند.)
- تست کردن و همچنین دیباگ کردن سیستمهای ایونت سورس بسیار ساده است. شما یک رفتار از سیستم را با ارسال یک کامند تریگر میکنید، و سپس انتظار لیستی از ایونتها را دارید. تست کردن سیستم نیز به همین راحتی است. If (I send the command) then I will expect these list of events همچنین با داشتن تمامی اطلاعات مربوط به تغییرات وضعیت برنامه درون یک فایل لاگ براحتی میتوانیم اقدام به دیباگ کردن سیستم کنیم.
<InTermsOfAggregateRoot<Customer, CustomerId
IfICreate(() => new Customer(customerId, masoudBahrami))
.ThenIWillExpectTheseEvents(new ANewCustomerIsCreatedEvent( customerId.Id, masoudBahrami.FirstName, masoudBahrami.LastName))
.And(a => a.FullName.FirstName == “Masoud” && a.FullName.LastName == “Bahrami”);
- Temporal Query یکی از مزیتهای بسیار مفیدی که ایونت سورس به ما میدهد این است که میتوانیم سیستم به هر وضعیت دلخواه در یک نقطه خاص از زمان برد. این کار به راحتی قابل انجام است. همچنین میتوانیم از این ویژگی جهت ریبیلد کردن یک ویوی جدید از وضعیت سیستم نیز استفاده کنیم.
تصور کنید مالک محصول اعلام میکند که آخرین سفارشی که صبح ساعت ۱۰:۱۵ ثبت کرده دچار خطا شده است. برای اینکه بتوانید وضعیت سیستم را در لحظهی بروز خطا داشته باشید، میتوانید براحتی سیستم را به ساعت ۱۰:۱۵ برده و در نتیجه وضعیت دقیق سیستم را در لحظه بروز خطا در اختیار داشته باشید.
- Auditing اولین و سادهترین مزیت سیستمهای Event Sourced داشتن یک لاگ کامل از تمامی تغییرات در برنامه است. تغییراتی که در بازههای زمانی مختلف در وضعیت برنامه رخ داده است. در حقیقت نیاز به داشتن Auditing نیازمندی جدیدی نیست که با Event Sourcing معرفی شده باشد. ما همیشه نیاز به Auditing برای کارهای مختلف داشتیم. جهت پاسخگویی به این نیازمندیها مجبور بودیم که کنار دیتابیسی که وضعیت برنامه را در آن ذخیره میکردیم یک فایل لاگ نیز از تغییرات برنامه(شامل نوع تغییر، کاربر، زمان تغییر، موفقیت آمیز بودن یا نبودن و دیتای تغییر یافته و …) نیز نگهداری میکردیم. در Event Sourcing ما یک قدم پیش رفتیم. در اصل ما از خود فایل لاگ نیز برای نگهداری وضعیت برنامه استفاده میکنیم. این تغییر نگاه جدید در مدیریت وضعیت برنامه است. بجای اینکه به سیتسم به عنوان State-Oriented نگاه کنیم به آن بصورت State-Transition نگاه میکنیم. در این دیدگاه همه تغییرات در فایل لاگ نگهداری میشود. بعدا از فایل لاگ برای مقاصد مختلف میتوان استفاده کرد. از جمله Auditing.
- سیر در زمان و عقب و جلو رفتن در زمان همیشه یکی از آرزوهای,های غیر قابل باور و دست یافتنی ما آدمها بوده است. این آرزوهای حتی در مورد سیستمهای نرمافزاری نیز بصورت غیرباور و دست نیافتی مینمود. اما به لطف Event Sourcing ما حداقل میتوانیم در مورد سیستمهای نرمافزاری بتوانیم براحتی در زمان حرکت کنیم. میتوانیم براحتی سیستم را به ۲۰ روز پیش عقب ببریم. میتوانیم براحتی سیستم به روز ۵ ژانویه ۲۰۲۲ ساعت ۱۳:۳۰ بعد از ظهر ببریم. همچنین میتوانیم در زمان جلو نیز برویم. مثل ۱ روز و ۵ ساعت بعد از ۵ ژانویه ۲۰۲۲٫ این ویژگی اغوا میکننده میتواند جواب بسیار از سوالاتی که با “what if …” شروع میشود را بدهد.
- Event-Driven Architecture مسلما یکی از نمودهای عینی معماریهای مبتنی بر Event سیستمهای Event Sourced است. در معماری EDA کامپوننتهای مختلف برنامه میتوانند با گوشدادن به ایونتهایی که از سایر کامپوننتها دریافت میکنند عکس العمل مناسب را اعمال کنند. این مورد یک انعطاف پذیری بسیار عالی در طراحی این سیستمها بدست میدهد. به عنوان فرض کنید که مشتری یک سفارشی را ثبت کرده است، و در انتظار پرداخت و نهایی کردن سفارش مشتری هستید. در این سناریو پس از ثبت سفارش مشتری، کامپوننت مدیریت سفارشات یک ایونت را پابلیش میکند. این ایونت توسط کامپوننت مدیریت مالی و پرداخت سیستم دریافت میشود. سپس این کامپوننت عملیات پرداخت کاربر را مدیریت کرده، و پس از پرداخت موفقیت آمیز، ایونت دیگری مبنی بر موفقیت آمیز پرداخت مرتبط با سفارش آن مشتری پابلیش میکند. حال سرویس مدیریت سفارش مشتری، میتواند با گوش دادن به این ایونت، براحتی سفارش مشتری را نهایی کند.
- Asynchrony همانطور که در مثال بالا نیز مشاهده میکنید، کامپوننتهای سیستم نیاز به کمترین همزمانی و ارتباط مستقیم با یکدیگر را دارند. کامپوننتها میتوانند تنها با گوش دادن به ایونتها عکسالعمل مناسب را نشان دهند. همچنین پاسخ آنها نیز میتواند در قالب ایونت باشد. در این سناریو حتی موقع پابلیش شدن یک ایونت ممکن است کامپوننت دیگر مشغول باشد، یا حتی بالا نباشد، اما میتواند پس از خالی شدن یا فعال شدن مجدد تنها با گوش دادن به ایونتهای مورد نظر، عملیات مورد نظر خود را انجام دهد.
- Autonomy ویژگی واکنش نشان دادن به ایونت این امکان را به کامپوننتهای سیستم میدهد که بدون کمترین وابستگی به یکدیگر بتوانند به کار خود ادامه دهند. در حقیقت یک کامپوننت تنها با گوش دادن به ایونتهایی که از خارج از دنیای خود دریافت میکند میتواند به حیات خود ادامه دهد. این ویژگی باعث میشود که تست پذیری این کامپوننتها نیز به شدت بالا برود.
به عنوان مثال فرض کنید قصد دارید سرویس سفارشات را تست کنید. میخواهیم در صورتی که پرداخت هزینهی سفارش با موفقیت انجام شد، سفارش مشتری را نهایی کنیم. در اینحالت از آنجایی که دو سرویس مدیریت سفارشات مشتری و مالی/پرداخت وابستگی مستقیمی با یکدیگر ندارند، میتوان براحتی تست مورد نظر را بر روی سرویس سفارشات انجام داد.
GIVEN There is an order pending payment
WHEN Received when the payment event of the order is completed successfully
THEN The order will be transferred to the final stage
در این سناریو میتوان به راحتی و تنها با دابل کردن دریافت آمیز ایونت مربوط به پرداخت موفقیت آمیز سفارش، اقدام به نوشتن تست اتوماتیک برای این سناریو شد. بدون اینکه سرویس مدیریت سفارشات مشتری، اطلاعی از وجود سرویس پرداخت/مالی داشته باشد.
پایان بخش چهارم