اوایل که سیستمهای نرم افزاری تازه داشتن شکل میگرفتن، همه چیز نسبتاً ساده بود. یه دیتابیس داشتیم که اطلاعات رو توش ذخیره میکردیم، تغییرات لازم رو اعمال میکردیم و دوباره ذخیره میکردیم. این روش تا وقتی که سیستمها ساده بودن، کاملاً جواب میداد. اما کم کم که نیازها پیچیدهتر شد، یه سؤال مهم پیش اومد: "چرا و چطور این تغییرات توی دادهها اتفاق افتادن؟"
بیایید با یه مثال ملموس جلو بریم. فرض کنید شما مدیر یه فروشگاه آنلاین هستید. توی روش قدیمی (بدون استفاده از Event Sourcing)، وقتی مشتری یه محصول رو میخره، شما فقط موجودی اون کالا رو توی دیتابیس به روزرسانی میکنید. مثلاً اگه یه جفت کفش از انبار خریداری بشه، موجودی از ۱۰ به ۹ کاهش پیدا میکنه. اما در این حالت فقط وضعیت نهایی رو میبینید و مشخص نیست چه مراحلی منجر به این تغییر شدن.
Event Sourcing اما یه نگاه جدید به این ماجرا داره. تو این روش، به جای اینکه فقط نتیجه نهایی رو ثبت کنیم، همه اتفاقاتی که باعث تغییر شدن رو ذخیره میکنیم. توی مثال فروشگاه آنلاین، این رویدادها میتونن شامل چیزایی مثل "اضافه شدن محصول به سبد خرید"، "تکمیل پرداخت"، "ارسال محصول" و "کاهش موجودی انبار" باشن. یعنی هر مرحله به دقت ثبت میشه.
این روش دو تا فایده اصلی داره: اول اینکه ردیابی و رفع اشکال رو خیلی راحتتر میکنه. مثلاً اگه مشتری بگه سفارش به دستش نرسیده، شما میتونید با نگاه کردن به تاریخچه رویدادها بفهمید که دقیقاً سفارش تو کدوم مرحله گیر کرده. دوم هم اینکه این دادههای تاریخی کلی ارزش برای تحلیلهای تجاری دارن، مثلاً اینکه بفهمیم کاربران چه رفتاری تو فرآیند خرید دارن و بتونیم بر اساسش استراتژیهای بازاریابی رو بهینه کنیم.
در نتیجه، Event Sourcing نه تنها یه تاریخچه دقیق از تمام تغییرات سیستم در اختیارمون میذاره، بلکه این امکان رو میده که بتونیم کسب وکارمون رو تحلیل و بهبود بدیم.

Event Sourcing یه الگوی طراحی نرم افزاریه که توش وضعیت یه سیستم به جای اینکه به شکل دادههای ثابت ذخیره بشه، به صورت یه سری رویداد ثبت میشه. این رویدادها تمام تغییراتی که تو طول زمان توی سیستم اتفاق افتادن رو نشون میدن و در واقع حکم "منبع اصلی حقیقت" یا همون Source of Truth رو دارن. هر کدوم از این رویدادها غیرقابل تغییر (Immutable) هستن و اطلاعات کاملی دارن که میتونیم با اونها وضعیت سیستم رو در هر لحظه ای از زمان دوباره بازسازی کنیم.
توی این روش، به جای اینکه مستقیم وضعیت فعلی رو ذخیره کنیم، سیستم تمام اتفاقاتی که منجر به وضعیت فعلی شدن رو نگه میداره. برای رسیدن به وضعیت فعلی، فقط کافیه این رویدادها رو یکی یکی مرور کنیم؛ به این کار Event Replay میگن. این روش چند تا مزیت بزرگ داره: اول اینکه قابلیت حسابرسی یا Audit کامل رو میده، یعنی هر لحظه میتونیم بررسی کنیم که چه اتفاقی افتاده و چرا. دوم اینکه میتونیم به وضعیتهای گذشته برگردیم، تغییرات رو تحلیل کنیم و حتی اگه جایی اشتباه شده باشه، اون خطاهای قدیمی رو هم اصلاح کنیم.
ببین، این الگو وقتی تو داری یک سیستم رو میسازی، هر تغییری که توی دادهها اتفاق میافته رو نگه میداره. یعنی به جای اینکه فقط حالت نهایی یه چیزی مثل دیتابیس رو داشته باشی، میتونی کل تاریخچه تغییرات رو ذخیره کنی. این جوری هر زمانی خواستی، میتونی برگردی و ببینی از اول چه اتفاق هایی افتاده و چرا به این نقطه رسیدی.
این کار به چند دلیل خوبه:
در کل، Event Sourcing یه جورایی مثل این میمونه که از همه چیز فیلم بگیری، نه فقط عکس. این جوری هر لحظه ای که بخوای، میتونی برگردی و لحظه به لحظه ببینی چی شده و چه تصمیماتی گرفته شده.
شیوه کار این الگو بر پایه یه ایده ساده ولی خیلی هوشمندانه بنا شده: اینکه هر تغییری که توی سیستم اتفاق میافته رو به عنوان یه رویداد ذخیره کنیم. برخلاف روشهای قدیمی که فقط نتیجه نهایی رو توی دیتابیس نگه میداشتن، Event Sourcing مثل یه دوربین فیلمبرداری میمونه که تمام لحظات و تغییرات رو ثبت میکنه و همیشه اونها رو حفظ میکنه.
برای اینکه بهتر متوجه بشیم، فرض کن مدیر یه فروشگاه آنلاین هستی. وقتی مشتری خریدی انجام میده، به جای اینکه فقط «فروش محصول» رو ثبت کنی، سیستم همه مراحل رو به عنوان رویدادهای جداگانه ذخیره میکنه. مثلاً:
"علی هدفون سونی رو به سبد خرید اضافه کرد - ساعت ۱۴:۳۰"
"پرداخت موفق برای سفارش #۱۲۳۴ انجام شد - ساعت ۱۴:۳۵"
"سفارش #۱۲۳۴ تحویل پست داده شد - ساعت ۱۶:۰۰"
این روش مثل اینه که یه ماشین زمان تو سیستم داشته باشی. هر موقع که بخوای، میتونی به عقب برگردی و دقیقاً ببینی چه اتفاق هایی افتاده. با بازپخش این رویدادها (Event Replay)، انگار داری یه فیلم رو تماشا میکنی و میتونی تمام جزئیات یه تراکنش رو از اول تا آخر ببینی و حتی وضعیت سیستم رو در هر لحظه ای از زمان بازسازی کنی. این شفافیت و امکان ردیابی دقیق، یکی از باارزشترین ویژگیهای Event Sourcing به حساب میاد.
Event Sourcing یکی از الگوهای معماری نرم افزاری پیشرفته ست که با یه روش خاص توی ثبت و مدیریت داده ها، قابلیتهای فوق العاده ای در اختیار توسعه دهندهها میذاره. با این حال، مثل هر تکنولوژی قدرتمند دیگه ای، استفاده از اون به بررسی دقیق مزایا و چالشها نیاز داره تا مطمئن شیم که برای پروژمون بهترین گزینه ست.
در نهایت، Event Sourcing یه رویکرد قدرتمند و ارزشمنده که علی رغم پیچیدگی هاش، میتونه تاثیر زیادی روی پروژههای نرم افزاری بذاره. با این حال، کلید موفقیت در استفاده از این الگو، اینه که اول نیازهای پروژه رو دقیق بررسی کنیم و مطمئن شیم که تیم از دانش و مهارت لازم برای مدیریت این معماری برخورداره.

پیاده سازی این الگو با استفاده از پایتون به این صورت کار میکنه که ما به جای ذخیره وضعیت نهایی یک سفارش، تمام رویدادها یا تغییراتی که روی اون سفارش اتفاق میوفته رو ذخیره میکنیم. این روش به ما اجازه میده که همه مراحل و عملیات انجام شده روی سفارش رو ثبت و نگهداری کنیم و در صورت نیاز دوباره اونها رو مرور کنیم. تو این مثال، میخوایم نشون بدیم چطور با استفاده از پایتون میتونیم یه سیستم ساده برای مدیریت سفارشها بسازیم که هر اتفاقی رو که برای هر سفارش افتاده، ثبت کنه و هر زمان نیاز داشتیم، دوباره وضعیت رو بازسازی کنه.
اول از همه، یه کلاس به نام Event تعریف میکنیم که نماینده هر رویدادیه که قراره روی سفارش اتفاق بیفته. این کلاس دو تا ویژگی داره: event_type که نوع رویداد رو نشون میده و data که شامل اطلاعاتیه که به اون رویداد مربوط میشه. به طور مثال، اگه رویداد اضافه کردن یه محصول به سبد خرید باشه، event_type میشه "add_item" و data میشه اطلاعات محصولی که اضافه شده، مثلاً اسم محصول.
class Event:
def __init__(self, event_type, data):
self.event_type = event_type
self.data = dataاین کلاس خیلی ساده ست و فقط نقش نگهداری اطلاعات هر رویداد رو داره. حالا هر وقت که بخوایم یه رویداد رو به سفارش اضافه کنیم، از این کلاس استفاده میکنیم تا رویداد رو تعریف کنیم.
بعد از تعریف کلاس Event، حالا میریم سراغ ساخت کلاس اصلی برای سفارش که اسمش رو Order میذاریم. این کلاس میتونه رویدادهایی رو که روی یه سفارش اتفاق میوفته، نگهداری و مدیریت کنه. هر سفارش یه order_id داره که شناسه منحصربه فرد اون سفارشه و یه لیست به نام events که همه رویدادهای مربوط به این سفارش رو توش ذخیره میکنیم. وقتی یه رویداد جدید اتفاق میوفته، اون رو به لیست رویدادها اضافه میکنیم.
class Order:
def __init__(self, order_id):
self.order_id = order_id
self.events = [] # لیست رویدادهای سفارشحالا میتونیم رویدادها رو به این سفارش اضافه کنیم. برای این کار، تابعی به اسم apply_event توی کلاس Order تعریف میکنیم که هر رویداد جدید رو دریافت میکنه و بر اساس نوعش عملیات مناسب رو انجام میده. این تابع به لیست رویدادها همون رویداد جدید رو اضافه میکنه و اگه لازم باشه، پیغامی نشون میده که توضیح میده چه اتفاقی افتاده.
در این تابع apply_event، چک میکنیم که نوع رویداد چیه و بر اساس نوعش، دستور مناسب رو اجرا میکنیم. مثلاً اگه رویداد از نوع "add_item" باشه، نشون میده که یه محصول به سبد خرید اضافه شده؛ اگه "confirm_order" باشه، یعنی سفارش تأیید شده و اگر "make_payment" باشه، مبلغ پرداخت شده رو نمایش میده. این کار باعث میشه که هر تغییر به صورت دقیق و قابل ردیابی ثبت بشه.
def apply_event(self, event):
self.events.append(event)
if event.event_type == "add_item":
print(f"Added {event.data['item']} to the cart.")
elif event.event_type == "confirm_order":
print(f"Order {self.order_id} confirmed.")
elif event.event_type == "make_payment":
print(f"Payment of {event.data['amount']} made.")
elif event.event_type == "ship_order":
print(f"Order {self.order_id} shipped.")حالا که کلاسهای Event و Order رو تعریف کردیم، میتونیم یه نمونه از سفارش ایجاد کنیم و رویدادهای مختلف رو به اون اضافه کنیم تا ببینیم چطور کار میکنه. فرض کنیم سفارش ما یک لپ تاپ داره که مشتری اون رو به سبد خرید اضافه کرده، بعد سفارش رو تأیید کرده، مبلغ رو پرداخت کرده و در نهایت سفارش ارسال شده. برای این کار از کد زیر استفاده میکنیم:
# حالا یک نمونه از Order ایجاد میکنیم
order = Order(order_id=1)
# رویدادها رو یکی یکی به سفارش اضافه میکنیم
order.apply_event(Event(event_type="add_item", data={"item": "Laptop"}))
order.apply_event(Event(event_type="confirm_order", data={}))
order.apply_event(Event(event_type="make_payment", data={"amount": 1000}))
order.apply_event(Event(event_type="ship_order", data={}))در اینجا، هر رویدادی که روی سفارش اتفاق میافته، به ترتیب به لیست رویدادها اضافه میشه. این کار باعث میشه که اگه در آینده نیاز داشتیم بفهمیم چه مراحلی طی شده، به راحتی بتونیم به این لیست مراجعه کنیم.
یکی از بزرگترین مزایای Event Sourcing اینه که به جای اینکه فقط وضعیت نهایی سفارش رو ذخیره کنه، همه تغییراتی که روی سفارش اعمال شده رو ثبت میکنه. این یعنی اگه هر وقت بخوایم بفهمیم دقیقاً چه کارهایی روی یه سفارش انجام شده، میتونیم به راحتی به تاریخچه رویدادها نگاه کنیم و همه چیز رو با جزئیات ببینیم.
از اونجایی که تمام رویدادها به ترتیب ذخیره شدن، اگه سیستم به هر دلیلی دچار مشکل بشه، میتونیم با بازپخش رویدادها وضعیت فعلی رو دوباره بسازیم. این یعنی اگه سیستم کرش کنه یا اطلاعات به هر دلیلی از بین بره، با اجرای دوباره این رویدادها، وضعیت قبلی سفارش رو میتونیم بازسازی کنیم و سیستم رو به حالت عادی برگردونیم.
در این مثال، دیدیم که چطور Event Sourcing به ما کمک میکنه که نه تنها همه تغییرات و رویدادها رو ثبت کنیم، بلکه امکان بازبینی و بازسازی وضعیت سیستم رو هم داریم. این الگو توی سیستمهای پیچیده و بزرگ، مثل سیستمهای مالی یا فروشگاههای آنلاین، خیلی مفیده چون میتونیم همیشه یه تاریخچه کامل از همه تغییرات داشته باشیم و هر وقت نیاز شد، وضعیت قبلی سیستم رو بازسازی کنیم. اینطوری همیشه خیالمون راحته که همه چیز ثبت شده و قابل ردیابی و بازسازی هست.
خب، بیایم یه نگاهی بندازیم به تفاوت الگوی این مقاله با روشهای دیگه ای که برای ذخیره سازی دادهها استفاده میشه. Event Sourcing ایده جذابی داره، ولی همیشه بهترین گزینه نیست. باید ببینیم چه مواقعی ازش استفاده کنیم و چه مواقعی بهتره بریم سراغ روشهای دیگه. بیایم روشهای مختلف رو با هم مقایسه کنیم.
تو ذخیره سازی سنتی، فقط وضعیت نهایی دادهها رو نگه میداریم. یعنی مثلاً وقتی چیزی توی سیستم تغییر میکنه، وضعیت جدید جایگزین وضعیت قدیمی میشه و دیگه نمیدونیم قبلش چه اتفاقی افتاده. برای همین اگه بخوای بفهمی چه اتفاقی باعث یه مشکل شده، نمیتونی برگردی عقب و دقیق تغییرات رو ببینی. اینجاست که Event Sourcing وارد میشه. توی این الگو، هر رویداد به صورت جداگانه ثبت میشه. یعنی هر تغییری که رخ میده، به عنوان یه رویداد ذخیره میشه و هر وقت خواستی میتونی به عقب برگردی و بفهمی چی شده.
اما خب، یه فرق مهم دیگه هم اینه که توی Event Sourcing حجم دادهها بیشتره. چرا؟ چون هر رویداد رو ذخیره میکنی، پس حجم دیتابیس با گذشت زمان زیاد میشه. ولی تو ذخیره سازی سنتی فقط وضعیت نهایی رو داری و حجمش کمتره.
حالا برسیم به CQRS. CQRS یه روش دیگه ست که یه جورایی با Event Sourcing هم میتونه ترکیب بشه. تو CQRS، فرمانها (که باعث تغییرات میشن) و پرس وجوها (که فقط دادهها رو میخونن) از هم جدا میشن. یعنی هر کدوم از این دو تا مسئولیت جدا دارن و توی دیتابیسهای جداگانه ذخیره میشن.
حالا ممکنه تو CQRS از Event Sourcing استفاده کنی یا از روش سنتی. مثلاً میتونی تو بخش فرمانها از Event Sourcing استفاده کنی که همه تغییرات رو نگه داری و تو بخش پرس وجو فقط دادههای نهایی رو بخونی. اینطوری هم میتونی تغییرات رو نگه داری، هم سریعتر به دادهها دسترسی پیدا کنی.
Snapshotting یه روشیه که تو Event Sourcing خیلی به درد میخوره. وقتی حجم رویدادها خیلی زیاد میشه و بازپخش همه رویدادها برای بازسازی وضعیت زمان بر میشه، میای از وضعیت کلی سیستم یه اسنپ شات (عکس لحظه ای) میگیری. بعد هر وقت خواستی وضعیت سیستم رو بازسازی کنی، به جای اینکه همه رویدادها رو از اول پخش کنی، میای از آخرین اسنپ شات استفاده میکنی و رویدادهای بعد از اون رو بازپخش میکنی.
این کار باعث میشه بازسازی سیستم سریعتر بشه، ولی همچنان پیچیدگی بیشتری نسبت به روشهای سنتی داره. هرچند که استفاده از Snapshotting میتونه به بهینه سازی سیستم کمک کنه.
مورد مقایسه | Event Sourcing | ذخیره سازی سنتی | CQRS | Snapshotting |
|---|---|---|---|---|
مدیریت تغییرات | تمام تغییرات ثبت میشن | فقط وضعیت نهایی نگه داری میشه | دستورات و پرس وجوها جدا هستن | عکس لحظه ای از وضعیت سیستم گرفته میشه |
بازگشت به حالت قبلی | امکان بازپخش رویدادها و بازسازی وضعیت | امکان بازگشت به گذشته نیست | می تونه با Event Sourcing ترکیب شه | بازگشت سریعتر با استفاده از اسنپ شات ها |
پیچیدگی پیاده سازی | پیچیده تره و نیاز به مدیریت رویدادها داره | سادهتر و مرسوم تره | ساده تره، ولی میتونه پیچیدهتر بشه | پیچیدگی کمتر با بازسازی از اسنپ شات |
حجم داده ها | حجم دادهها زیاد میشه | حجم کمتر چون فقط داده نهایی نگه داری میشه | بستگی به مدل دادهها داره | حجم پردازش کمتر با اسنپ شات ها |
همونطور که دیدی، Event Sourcing خیلی به درد سیستم هایی میخوره که نیاز به نگهداری تاریخچه تغییرات دارن و سیستمهای پیچیده ای هستن. اما خب، همیشه بهترین گزینه نیست و باید حواست باشه که پیچیدگیها و هزینههای خودشو داره.

Event Sourcing یه الگوی معماریه که به جای ذخیره سازی فقط وضعیت نهایی داده ها، تمام تغییرات و رویدادها رو به شکل جداگانه ثبت و ذخیره میکنه. این کار باعث میشه که بتونیم تاریخچه کامل هر تغییر رو داشته باشیم و هر وقت لازم شد، وضعیت سیستم رو دوباره بسازیم.
Event Sourcing زمانی استفاده میشه که به تاریخچه کامل رویدادها، امکان برگشت به حالتهای قبلی و تحلیل دقیق تغییرات نیاز داریم. این الگو برای سیستمهای پیچیده مثل سیستمهای مالی، فروشگاهی و بانکی خیلی مناسبه.
توی ذخیره سازی سنتی، فقط وضعیت نهایی دادهها ذخیره میشه؛ ولی توی Event Sourcing هر تغییر به عنوان یک رویداد ثبت میشه. این یعنی میتونیم به تاریخچه کامل تغییرات دسترسی داشته باشیم و حتی رویدادها رو دوباره بازپخش کنیم.
بله، چون هر تغییری به شکل یه رویداد ذخیره میشه، با گذشت زمان حجم دیتابیس زیاد میشه. برای کنترل این موضوع، میشه از تکنیک هایی مثل آرشیو کردن رویدادهای قدیمی استفاده کرد.
برای پیاده سازی Event Sourcing، به جای ذخیره وضعیت نهایی، باید تغییرات یا رویدادها رو ثبت کنیم. فریم ورکها و ابزارهایی مثل Akka، Axon Framework و EventStore میتونن توی پیاده سازی این الگو کمک کننده باشن.
بله، Event Sourcing نسبت به روشهای سنتی پیچیدگی بیشتری داره. طراحی و پیاده سازی این الگو نیاز به مهارت و تجربه داره و باید از ابزارها و تکنیکهای مناسب برای ذخیره و بازیابی رویدادها استفاده بشه.
Event Sourcing بیشتر برای سیستمهای پیچیده کاربرد داره. برای سیستمهای کوچیک یا جایی که نیاز به نگهداری تاریخچه دقیق نداریم، پیچیدگی و هزینههای پیاده سازی این الگو ممکنه به صرفه نباشه.
Event Sourcing یه روش قدرتمنده که بهت اجازه میده تاریخچه دقیق همه تغییرات سیستم رو ثبت کنی. این روش برای سیستمهای پیچیده که نیاز به تحلیل، دیباگ و بازسازی وضعیت دارن فوق العاده مفیده. البته باید بدونی که با این روش، حجم دیتابیس بزرگتر میشه و طراحی سیستم نیاز به دقت بیشتری داره. اما در نهایت، اگه سیستم پیچیده ای داری و میخوای هیچ اتفاقی رو از دست ندی، Event Sourcing گزینه ی خوبیه.
حالا که فهمیدی Event Sourcing چیه، وقتشه بری دست به کار شی و توی سیستمهای خودت پیادش کنی. با ثبت کردن هر رویداد، کنترل کامل رو روی سیستم داری و میتونی هر وقت خواستی، برگردی و بفهمی چی گذشته. به قول معروف، "تاریخچه همیشه حرفی برای گفتن داره!"
دوره الفبای برنامه نویسی با هدف انتخاب زبان برنامه نویسی مناسب برای شما و پاسخگویی به سوالات متداول در شروع یادگیری موقتا رایگان شد: