as web is growing
in complexity and size
simple CMS
simple webshops
existing practices
Good old days
<html>
<?php
$mysql = mysql_connect(....);
$users = mysql_fetch('SELECT * FROM ...');
?>
<table>
<?php for($i=0;$i<count($users);$i++){ ?>
<tr>
<td><?php echo $users[$i]['first_name']; ?> </td>
...
</tr>
...
<?php
if( $x = 123) {
echo '<span> .... </span>';
}
?>
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 | 2018-12-04 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, ' 2018-12-04 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 engineer / contractor
@msvrtan
My ES + CQRS experience
3 years Year with EventSourcing & CQRS
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
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 PHP Lisbon meetup (2018-12-04)
- 1,573