به بیان ساده Event sourcing راهکاری برای ذخیره سازی حالت یک شی بر اساس رخداد هایی [1] است که از زمان ایجاد برای آن اتفاق افتاده است. در این صورت قادر خواهیم بود حالت هر شی در هر لحظه از زمان را با بازسازی این رخدادها، ایجاد کنیم. هر چند فواید بسیاری بر این روش مترتب است، نباید از جان مایه آن که توجه به رفتار [2] به جای حالت [3] است غافل شد.  سایر مزایای استفاده از این روش عبارتند از :

  • تغییر در سازوکار ذخیره سازی، تغییری در برنامه ایجاد نمی کند.
  • به خاطر سادگی ذخیره سازی رخدادها، کارایی بهبود می یابد.
  • عدم نیاز به لایه orm [4] برای ذخیره سازی.
  • نگهداری تاریخچه رخدادهایی که در سیستم اتفاق افتاده است.
  • سادگی تجمیع [5] با سایر زیر سیستم ها.
  • سیر در گذشته و پیش بینی آینده.
  • خطایابی سیستم که در حال کار است با تکرار رخداد هایی که منجر به خطا شده اند.

سناریوی اصلی پیاده سازی این الگوی معماری در قطعه کد زیر نشان داده شده است. با هر درخواست در لایه application service، شناسه aggregate root ای که برای پاسخ گویی به این درخواست وظیفه ای برعهده دارد مشخص می شود. سپس رخدادهایی که تا این لحظه برای این شی اتفاق افتاده است از منبع ذخیره سازی رخداد ها [6] دریافت می شود. با دریافت این رخدادها و اعمال آنها به شی مورد نظر، این شی به حالتی قبل از ورود درخواست می رسد. سپس بر اساس درخواست ورودی، متدی روی شی مورد نظر فراخوانی می شود. در پاسخ به این متد فراخوانی شده، دنباله ای از رخداد ها اتفاق می افتد که شی مورد نظر این دنباله را در اختیار دارد. در ادامه رخدادهای اتفاق افتاده در منبع ذخیره سازی رخدادها ذخیره می شود و پاسخ درخواست ورودی، ارسال می شود.


public Customer EsRoutine(Guid id, Action<Customer> action)
{
    var events = _eventStore.Get(id);

    var customer = new Customer(events);

    action(customer);

    _eventStore.Save(customer.Id, customer.Changes);

    return customer;
}


کد منبع مربوط به این پست از این آدرس قابل دریافت است.

هر چند این الگو مزایای زیادی به دنبال دارد، استفاده از آن چالش هایی به همراه دارد. اول اینکه با توجه به اینکه با هر درخواست ورودی می بایست aggregate root درگیر در این درخواست را با اعمال رخدادهایی که تا کنون اتفاق افتاده است به حالت فعلی رساند، در صورتی که تعداد این رخدادها زیاد باشد باعث ایجاد سربار بالایی برای سیستم خواهد شد. استفاده از snapshot و cache دو راه معمول برای حل این مشکل است. از طرف دیگر هر چند ذخیره سازی به صورت blob [7] و clob [8] باعث سادگی درج [9] اطلاعات می شود اما جستار [10] اطلاعات ذخیره شده با این روش ها مقرون به صرفه نیست. استفاده از الگوی cqrs [11] راه حلی شناخته شده برای این مشکل است که انشاا... در پست های آتی مورد بررسی قرار خواهد گرفت. 



[1] - Event

[2] - Behavior

[3] - State

[4] - Object Relational Mapper

[5] - Integration

[6] - Event store

[7] - Binary Large OBject

[8] - Character Large OBject

[9] - Insert

[10] - Query

[11] - Command Query Responsibility Segregation