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)
- 2,093