Search code examples
microservicesdomain-driven-designcqrsevent-sourcing

How to manage read requests in an event sourced application


I was asked to do some exploration in event sourcing. my objective is to create a tiny API layer that satisfies all the traditional CRUD operation. I am now using a package called 'sourced' and trying to play around with it (Using Nodejs).

However, I came to realize that the event sourcing is not quite useful when it is used alone. usually, it is coupled with CQRS.

My understanding of the CQRS is, when the UI sends a write command to the server. the app does some validation towards the data. and saves it in the event store(I am using mongoDB), for example: here is what my event store should look like:

{method:"createAccount",name:"user1", account:1}
{method:"deposit",name:"user1",account: 1 , amount:100}
{method:"deposit",name:"user1",account: 1 , amount:100}
{method:"deposit",name:"user1",account: 1 , amount:100}
{method:"withdraw",name:"user1",account1,amount:250}

It contains all the audit information rather than the eventual status. however, I am confused how can I handle the read operation. what if I want to read the balance of an account. what exactly will happen? here are my questions:

  1. If we can not query the event store(database) directly for reading operation, then where should we query? should it be a cache in memory?
  2. If we query the memory. is the eventual status already there or I have to do a replay (or left-fold) operation to calculate the result. for example, the balance of the account 1 is 50.
  3. I found some bloggers talked about 'subscribe' or 'broadcast'. what are they and broadcast to who?

I will be really appreciated for any suggestion and please corret me if my understanding is wrong.


Solution

  • Great question Nick. The concept you are missing is 'Projections'. When an event is persisted you then broadcast the event. You projection code listens for specific events and then do things like update and create a 'read model'. The read model is a version of the end state (usually persisted but can be done in memory).

    The nice thing is that you can highly optimise these read models for reading. Say goodbye to complicated and inefficient joins etc.

    Becuase the read model is not the source of truth and it is designed specifically for reading, it is ok to have data duplication in it. Just make sure you manage it when appropriate events are received.

    For more info check out these articles:

    Hope you find these useful.

    ** The diagram refers to denormalisation where it should be talking about projections.