Year with EventSourcing & CQRS

as web is growing

in complexity and size

simple CMS

simple webshops

existing practices

MVC

CRUD

existing practices 

Clean architecture vs performance

id 123
title Register button doesnt work in IE
assigned null
type BUG
status OPEN
priority URGENT
createdAt 2016-03-11 22:22:11
updatedAt 2017-10-26 08:01:35
closedAt

Issue tracker: Issue

What if we record all changes?

IssueCreated(123, 'Something', 'text', BUG, NORMAL, ' 2016..')

IssueAssigned(123, TeamManager, ' 2016-03-12 10:00:00')

PriorityChanged(123,URGENT, ' 2016-08-11 15:46:33')

IssueDellocated(123,'2016...')

IssueClosed(123,'2016...')

IssueReopened(123, ' 2017-10-26 08:01:35')

TitleChanged(123, ' Register button doesnt work in IE', '2016...')

and create state from applying them?

event sourcing

issue

678

number of issues opened today

abc123-123-121313

daa-2-2-3-3-2-3-2

unassigned urgent issue ids

abc-123-23  Login doesnt work       85

acd-342-43  Bug X                              75

open issues with number of comments

Command Query Responsibility Segregation

Miro Svrtan

trainer / senior developer / contractor

 

ZgPHP organizer

 

@msvrtan

My ES + CQRS experience

project X

devboard

External concerts on TicketSwap

Defining bounded context

You as a TicketSwap user:

  • can sell tickets
  • can buy tickets
  • just use the site

In "boring" domain

In a startup

Concentrate on bringing value not perfect code

Saga/process manager

Queues

And worst enemy

Your best friend

Eventual consistency

  • never blindly trust your read model data
  • aggregates are ONLY source of truth

Domain - application - infrastructure separation

Saving invoice into RDBMS

blog post + comments

in NoSQL

Domain - application - infrastructure separation

Writing tests

Skip ES + CQRS if no testing experience

Writing tests

  • don't test state of aggregate
  • concentrate on unit/integration testing
  • do some end-to-end tests

Mock the infrastructure

  • not locked to infrastructure while developing
  • 10-100x faster testing 

Performance

Loading aggregate

    <10 events                   10 ms

    ~50 events                   20 ms

  ~100 events                   50 ms

~2000 events              1500 ms

Big aggregate root example

  • ~700 entities inside
  • 650.000 events

Snapshotting

Snapshotting DIY

  • creates a snapshot every ~200 events
  • 17Mb of payload
  • aggregate load time < 100ms

UUIDs

UUID performance

"64c3e987-905a-4426-8dc3-ddb61650b86b"

vs

123456

Class number explosion

  • UserController
  • User (Entity)
  • UserRepository
  • UserController
  • RegisterUserCommand
  • UserCommandHandler
  • User (Aggregate)
  • UserRepository
  • UserRegisteredEvent
  • UserReadProjector
  • UserReadEntity
  • UserReadRepository

Class number explosion

  • UserController
  • User (Entity)
  • UserRepository
  • UserController
  • RegisterUserCommand
  • ChangePasswordCommand
  • UserCommandHandler
  • User (AggregateRoot)
  • UserRepository
  • UserRegisteredEvent
  • PasswordChangedEvent
  • UserReadProjector
  • UserReadEntity
  • UserReadRepository

No read side logic

Building read side:

replaying events

Use familiar tech

ES+CQRS is a big shift in thinking

Final words

Thank you!

@msvrtan

Any questions?

Year with EventSourcing and CQRS

By Miro Svrtan

Year with EventSourcing and CQRS

Slides for my 'Year with EventSourcing and CQRS' on International PHP Conference, Munich, Germany (2017-10-26)

  • 503

More from Miro Svrtan