Event Sourcing بخش سوم
لیست مطالب آموزشی Event Sourcing:
- بخش اول مقدمهای بر Event Sourcing
- بخش دوم آشنایی مقدماتی با ساختار داخلی Event Store
- مقایسه رویکردهای State-Oriented و State-Transition
- مزیتهای Event Sourcing
- سلام به دنیا به روش Event Sourcing
- سلام به دنیا به روش Event Sourcing-بخش دوم
- بخش هفتم Projection
- بخش هشتم ویرایش ایونت ها در EventSourcing
- بخش نهم Message، Command یا Event
مقایسه State-Oriented و State-Transition
در پست قبلی مورد ساختار داخلی Event Storeها صحبت کردم. همچنین برخی از بلاکهای سازنده Event Sourcing را معرفی و مورد بررسی قرار دادم. پیشنهاد میکنم قبل از مطالعه این مطلب، پست قبلی را مطالعه کنید. در این پست با دو رویکرد متفاوت مدلسازی مدیریت State برنامه آشنا خواهید شد. این دو رویکرد State-Oriented و State-Transition است.
۳٫۱- مقدمه
اکثر برنامههایی که توسعه میدهیم، صرفنظر از بزرگی یا کوچیکی و نوع برنامه، در نهایت ما state یکسری resource را در در جایی ذخیره کنیم. این state را بعدا واکشی کرده و به کاربر نمایش میدهیم. این نمایش state به عنوان مکانیزم پشتیبانی تصمیم کاربر مورد استفاده قرار میگیرد. تصمیم بعدی کاربر در سیستم، ممکن است منجر به تغییر state برنامه شود. این تغییرات را مجدد در مکانیزم ذخیره سازی نگهداری میکنیم. این چرخه همیشه ادامه پیدا میکند.
دو رویکرد مختلف جهت ذخیره سازی وضعیت برنامه وجود. این دو رویکرد به نوعی نقطه مقابل یکدیگر هستند. هر کدام از این روشها ویژگیهای منحصر بفردی دارند. در ادامه این رویکرد را معرفی خواهم کرد.
۳٫۲- State-Oriented Mechanism
در رویکرد State Oriented ما همیشه آخرین وضعیت برنامه(last state) را نگه میداریم. اگر هر تغییری ولو کوچک در وضعیت یک resource در برنامه رخ بدهد آخرین وضعیت آنرا نگه میداریم. بدین معنی که اگر resource قبلا در دیتابیس وجود نداشته باشد، آنرا ایجاد میکنیم، و اگر وجود داشته باشد، state آن resource را آپدیت کرده و تغییرات را بر روی دیتای قبلی در دیتابیس overwrite میکنیم.
با یک مثال مطلب روشنتر میشود. فرض کنید Masoud Bahrami یک حساب بانکی باز کرده است. او میتواند بعدا به این حساب بانکی خود پول واریز کرده یا از آن برداشت کند. به این ترتیب بالانس حساب بانکیاش در هر زمان میتواند بالا یا پایین برود. به عنوان مثال تصور کنید Masoud حساب بانکی را با موجودی اولیه $۱۰۰ باز کرده است. در نتیجه state برنامه بعد از باز کردن حساب توسط Masoud بصورت زیر خواهد بود.
اگر تراکنش بعدی Masoud بر روی این حساب، واریز کردن $۱۰۰ دیگر به حساب بانکیش باشد، پس بالانس حساب $۲۰۰ خواهد شد. بعد از اعمال این تراکنش وضعیت جدید حساب بر روی وضعیت قبلی ذخیره شده overwrite میشود. بدین ترتیب ما همیشه آخرین وضعیت را نگه داری خواهیم کرد.
۳-۲-۱- مزیتهای State-Oriented Mechanism
رویکرد State-Oriented با خط فکری ما نسبت به ذخیره سازی state برنامه سازگار است. این روشی است که اکثر ما نسبت به ذخیره سازی وضعیت یک برنامه تصور میکنیم. RDBMSها و حتی دیتابیس NoSQL کاملا منطبق بر این ساختار هستند. آپدیت کردن و overwrite کردن وضعیت یک resource درون دیتابیس بر اساس state جدید.
میتوان گفت سادگی مکانیزم سادهسازی مهمترین مزیت State-Based است. همچنین ما در بیشتر مواقع نیاز داریم که آخرین وضعیت یک resource را به کاربر نمایش دهیم. از آنجایی که آخرین وضعیت نیز در دیتابیس ذخیره میشود، در نتیجه نمایش این آخرین وضعیت، به سادگی یک fetch کردن ساده از دیتابیس میتواند باشد. از آنجایی که آخرین وضعیت یک resource در دیتابیس ذخیره میشود(این وضعیت در RDBMS میتواند با چالش impedance mismatch همراه باشد) میتوانیم به راحتی با لینک کردن resource های مختلف در سطح دیتابیس، نمایش هایی غنی از اطلاعات را به کاربر به سادگی نمایش دهیم.
به عنوان، حساب بانکی و صاحب حساب در بالا را نظر بگیرد. اگر این resource ها در یک RDBMS ذخیره شوند، میتوان به راحتی با افزودن یک کلید خارجی بین table های متناسب با این resourceها، به راحتی جزئیات یک حساب را به همراه اطلاعات دقیق صاحب حساب را نمایش دهیم.
به عنوان یک مثال دیگر، سند حسابداری(Financial Transaction) را در نظر بگیرید. هر سند شامل لیستی از آرتیکلها(Transaction Entry) است. اگر این ساختار را در یک RDBMS ذخیره کنیم، جداول آنها میتواند چیزی شبیه به تصویر پایین باشد.
همانطور که در این مثال پیچیدهتر نیز مشاهده میکنید، میتوان راحتی با افزودن یک کلید خارجی در جدول Transaction Entry به این دو جدول برقرار کرد. با اینکار نمایش آخرین وضعیت سند د ر هر لحظه میتواند بسادگی اجرا کردن کوئری زیر باشد.
SELECT * from financial_transaction_tbl AS ft
INER JOIN transaction_entry_table AS te
ON ft.Id = te.financial_transaction_id
WHERE ft.id=1
۳٫۳- State-Transition Mechanism
در رویکرد State-Transition بر خلاف رویکرد State-Oriented تنها به ذخیره دیتا و آخرین وضعیت هر resource اکتفا نمیکند. در این دیتابیسها همانطور که از اسم آنها مشخص است، وضعیتهای مختلفی که یک resource در طول زمان بین آنها جابجا میشود را نیز ذخیره میکند. این moveشدن بین stateهای مختلف در برنامه در قالب Event مشخص شده و و در انتهای مکانیزم ذخیرهسازی append میشود.
در حقیقت یک Event تغییراتی که در یک لحظه خاص در برنامه رخ داده است، را در خود رکورد میکند. میتوان Event را به مثابه یک فریم از یک فیلم در نظر گرفت. در نهایت این Event به درون فایل لاگ ذخیره میشود. همانطور که میتوان مشاهده کرد، با اینکار ما نه تنها تغییرات داده در آن لحظه از زمان را داریم، بلکه دلیل تغییر بوجود آمده را نیز خواهیم داشت. State Transition در حقیقت Eventهایی هستند که آن چیزی که در state برنامه شما تغییر کرده است، را ثبت کرده و در فایل لاگ به عنوان دیتابیس ذخیره میکند. این باعث میشود که یک لاگ غیر قابل تغییر و دائمی از تمامی تغییرات state برنامه بصورت کامل داشته باشیم.
به عنوان یک مثال سند حسابداری را در نظر بگیرید. تغییر وضعیتهای مختلف این سند را میتوان بصورت Event های زیر رکورد کرد.
Event شبیه یک فریم از یک فیلم است. همانطور که یک فریم، یک شات از یک لحظه خاص در آن فیلم رو رکورد میکند، Event نیز state برنامه را در یک پوینت زمانی خاص رکورد میکند.
همانطور که در مثال بالا مشاهده، ما هیچوقت آخرین وضعیت سند حسابداری را بر روی وضعیت قبلی overwrite نمیکنیم. در عوض تمامی تغییر وضعیتهایی که بر روی این سند رخداده است را به همراه دلیل آن تغییر، درون stream مربوطه append میکنیم. از stream بالا میتوانیم متوجه شویم که در بازه زمانی t4 سند یک تغییر کرده، و دلیل آن تغییر تائید شدن سند حسابداری بوده است. درون هر Event تغییرات رخداده شده نیز رکورد میشود.
به عنوان مثالی دیگر حساب بانکی را نظر بگیرید. فرض کنید این حساب با موجودی اولیه $۱۰۰ باز شده باشد. فرض کنید در زمانهای t1 تا t4 تراکنشهای رخ داده بر روی این حساب به صورت زیر باشد:
- $۱۰۰ واریز کند.
- $۵۰ برداشت کند.
- $۱۰۰ واریز کند.
در این حالت این تغییر وضعیتهای رخ داده بر روی این حساب بصورت زیر در stream مربوطه ذخیره خواهد شد.
همانطور که اشاره شد Event شبیه یک فریم از یک فیلم، تصویری از وضعیت برنامه در یک پوینت زمانی خاص را به ما میدهد. همانطور که یک فیلم تشکیل شده است از مجموعهای از فریمهایی که پشت سر همدیگر اجرا میشوند. ما نیز برای اینکه تغییر وضعیتهای resource برنامه را مشاهده کنیم و همینطور جهت اینکه آخرین وضعیت آن resource را داشته باشیم، باید فریمهای آن resource که در قالب Event رکورد شدهاند را پشت سر هم قرار دهیم.
برای مثال حساب که در بالا آورده شد، میتوان براحتی آخرین وضعیت حساب، یا در حقیقت بالانس حساب را با اعمال کردن پشت سر هم Eventهای آن بدست آورد.
$۱۰۰ + $۱۰۰ – $۵۰ + $۱۰۰ = $۲۵۰
Event Sourcing یکی از مهمترین نمودهای State-Transitionها در عمل میباشد. بصورت خلاصه در این رویکرد هیچوقت دیتاهای قبلی رو overwrite نمی شود. هر کدام از این state transition ها در یک stream ذخیره میشوند. میتوان بعدا از این stream خواند یا بر روی آن کوئری اجرا کرد. میتوانید این stream را به هر طریقی که میخواهید پیمایش کنید. همچنین با توجه به اینکه تمامی تغییرات و دلیل آن تغییرات را در این فایل لاگ داریم، این میتواند قدرت و بینشی که جهت تصمیمگیری مبتنی بر داده نیاز دارید را به شما بدهد.
در مورد مزیتهای این رویکرد در مقاله بعدی مفصل صحبت خواهم کرد.
پایان بخش سوم