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 2019-01-09 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, ' 2019-01-09 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

 

@msvrtan

 

miro@mirosvrtan.me

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

Feedback appreciated: https://joind.in/talk/9fd23

Any questions?

Year with EventSourcing and CQRS

By Miro Svrtan

Year with EventSourcing and CQRS

Slides for my 'Year with EventSourcing and CQRS' on SunshinePHP

  • 1,944