Event sourcing and command sourcing

· Read in about 3 min · (500 words) ·

Notes based on playing and researching the Event Sourcing & Command Sourcing.

This is closely related to microservices if applied properly.

Event sourcing and command sourcing

Overview

  • Good segregation of application logic in terms of data modification and querying
    • This should simplify reasoning about the application logic
    • Since all modifications are just a stream of events it avoids side-effects people tend to put into read logic
    • Also allows to have optimal models for each of above
  • Improved scalability - write part is append-only so it reduces locking complexity
  • If read model is updated asynchronously then not very well suited for complex screens where user can edit many fields and assumes upon save to get refreshed data
  • Well suited for task oriented UI
  • Commands - requested actions to be performed on the model, should be named as verbs
    • Commands are immutable - they live just for short time of transfer from caller to command handler
  • Events - performed model state changes, should use past tense (something happened and it cannot be undone)
    • Events are immutable - past cannot be changed
    • Stored in a sequential log which can be later used for analysis of what happened in the system
    • Can be used later to update for example querying model
    • Fixing a state change should be done by adding another event which reverts the previous operation

Dealing with concurrency

  • Pretty simple:
    • Event can contain ‘version’ of model which is being updated
    • Event log then can have a unique constraint for each aggregate id and model version
    • Assuming two or more concurrent actions updated the same aggregate on same version one of the updates will fail
    • Command handler then can decide:
      • Retry the same operation with some merge logic
      • Fail the operation
    • This constraint can be implemented in relation database as well as other services (like Google Firebase).

Operations which require multiple aggregates

  • In monoliths usually a transaction covering multiple tables
  • In microservices this would usually mean at least distributed transaction
    • Often this is just not possible since some systems simply do not support it or even worse - have just limited or no transactional support
  • This can be to some degree solved by saga pattern
    • Either flow of events processed asynchronously as the individual services progress in processing
    • Or performed from one place as a sequence of steps which subsequently update states

Challenges

  • Defining right aggregate
    • This is crucial since each aggregate then has own event log etc.
    • Aggregate should never perform operations outside itself
    • As result in relation database this wouldn’t need FK constraints
  • What belongs to command handler vs. event handler?
    • This seems to be sometimes a bit unclear and even various sources have various requirements - e.g. where belongs sending an email - to command handler or to event handler?
  • Rebuilding model from events each time may be slow - some kind of caching may be needed - memory cache can be used for this.
  • Dealing with structural changes of commands and events due to bugfixing etc.