$30 off During Our Annual Pro Sale. View Details »

TOTAL RECALL - The application that never forgets

TOTAL RECALL - The application that never forgets

Building an application upon CQRS and Event Sourcing offers three pretty nice benefits.

1. Well structured code and business logic, separated by read and write concerns.
2. The source of truth - A reliable and recoverable view into the past of your application state.
3. The opportunity to answer future questions that you don't know about today.

This talk tries to show you examples for these benefits and how to give your application a memory.

At #PHPkonf 20th of May 2017 in Istanbul, Turkey

Holger Woltersdorf

May 20, 2017
Tweet

More Decks by Holger Woltersdorf

Other Decks in Programming

Transcript

  1. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    1 MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    THE APPLICATION THAT NEVER FORGETS

    View Slide

  2. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    2
    IT’S MY WIFE’S
    BIRTHDAY
    HELP!

    View Slide

  3. HOLGER WOLTERSDORF
    CIO • FATHER • HUSBAND • PHP DEV WITH ♥
    github.com/hollodotme
    @hollodotme

    View Slide

  4. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    4

    View Slide

  5. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    5
    SEPTEMBER 22nd
    ARNE
    BLANKERTS
    thePHPcc
    SEBASTIAN
    HEUER
    kartenmacherei
    JAN
    BURKL
    ZEND
    MARCO
    PIVETTA
    Ocramius
    STEPHAN
    HOCHDÖRFER
    bitExpert
    ALEXANDER
    MIERTSCH
    prooph software
    CHRISTIAN
    LÜCK
    reactPHP

    View Slide

  6. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    6
    CQRS
    (COMMAND QUERY RESPONSIBILITY SEGREGATION)

    View Slide

  7. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    CQS => CQRS
    7
    ๏ CQRS EVOLVED FROM THE CQS IMPLEMENTATION PATTERN
    ๏ First stated by Bertrand Meyer in the 1990’s 

    when working on the Eiffel programming language

    ๏ Describes a semantic implementation pattern for object methods
    ๏ Queries: return results, but do not change the observable state (free of side effects)
    ๏ Commands: change the state of objects, but do not return values
    Bertrand Meyer

    View Slide

  8. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    CQS => CQRS
    8
    class Number
    {
    /** @var int */
    private $number = 0;
    public function getIncrementedNumber() : int
    {
    $this->number++;
    return $this->number;
    }
    }
    BAD

    View Slide

  9. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    CQS => CQRS
    9
    class Number
    {
    /** @var int */
    private $number = 0;
    public function getNumber() : int # Query
    {
    return $this->number;
    }
    public function increment() : void # Command
    {
    $this->number++;
    }
    }
    GOOD

    View Slide

  10. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    CQS => CQRS
    10
    ๏ CQRS IS AN ARCHITECTURE PATTERN
    ๏ Described by Greg Young’s CQRS documents in 2010
    ๏ One part responsible to represent the current state of the application
    ๏ One part responsible to change the state of the application
    ๏ Command and Query have a broader semantic meaning than in CQS
    ๏ Key concept is to split your application into:
    ๏ A read side that is able to answer queries (read-only)
    ๏ A write side that is able to process commands (write-only)
    ๏ Give each side an appropriate storage
    GREG YOUNG

    View Slide

  11. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    11
    CQRS DEMO

    View Slide

  12. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    12
    THREE APPLICATION LAYERS
    REQUEST HANDLING LAYER
    BUSINESS LOGIC LAYER
    PERSISTENCE LAYER
    CQRS CAN BE APPLIED TO ALL OF THEM
    KNOWS
    HTTP
    KNOWS
    BUSINESS
    RULES
    KNOWS
    DATABASE

    View Slide

  13. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    13
    THREE APPLICATION LAYERS
    READ REQUESTS
    BUSINESS LOGIC
    REPRESENTATION
    WRITE REQUESTS
    STATE
    AFTER CQRS WAS APPLIED
    VIEW LOGIC

    View Slide

  14. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    14
    THREE APPLICATION LAYERS
    READ REQUESTS
    BUSINESS LOGIC
    REPRESENTATION
    WRITE REQUESTS
    STATE
    HOW DO WE GET FROM HERE… … TO THERE?
    VIEW LOGIC

    View Slide

  15. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    15
    THREE APPLICATION LAYERS
    READ REQUESTS
    BUSINESS LOGIC
    REPRESENTATION
    WRITE REQUESTS
    STATE
    PUBLISH SUBSCRIBE
    REDIRECT (+ SESSION)
    VIEW LOGIC

    View Slide

  16. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    REPRESENTATION
    16
    THREE APPLICATION LAYERS
    READ REQUESTS
    BUSINESS LOGIC
    REPRESENTATION
    WRITE REQUESTS
    STATE
    VIEW LOGIC
    PUBLISH SUBSCRIBE
    REDIRECT (+ SESSION)
    REPRESENTATION
    MESSAGE
    BROKER
    ASYNC
    EVENTUAL
    CONSISTENCY
    !

    View Slide

  17. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    REPRESENTATION
    17
    THREE APPLICATION LAYERS
    READ REQUESTS
    BUSINESS LOGIC
    REPRESENTATION
    WRITE REQUESTS
    STATE
    VIEW LOGIC
    PUBLISH SUBSCRIBE
    REDIRECT (+ SESSION)
    REPRESENTATION
    PHP FASTCGI
    CLIENT
    ASYNC
    EVENTUAL
    CONSISTENCY
    !

    View Slide

  18. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    18
    CQRS (REQUEST HANDLING LAYER)
    ๏ GET-REQUEST
    ๏ NO VIEW LOGIC
    ๏ COULD BE A STATIC

    HTML PAGE
    ๏ SUBMIT TRIGGERS

    POST REQUEST

    View Slide

  19. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    19
    CQRS (REQUEST HANDLING LAYER)
    ๏ GET-REQUEST 

    AFTER REDIRECT
    ๏ CHECK FOR ERRORS 

    IN SESSION
    ๏ ERRORS RENDERED
    INTO VIEW
    ๏ ONLY SUBMIT 

    TRIGGERS POST
    REQUEST
    ๏ RELOAD DOESN’T

    View Slide

  20. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    CQRS (REQUEST HANDLING LAYER)
    20
    class POSTRequestHandler
    {
    public function handle( $request, $session ) : void
    {
    #...
    $validator->checkUserInput( $request );
    if ( $validator->failed() )
    {
    $session->addErrors( $validator->getErrors() );
    (new Redirect())->respond( '/newsletter-form' );
    return;
    }
    #...
    }
    }

    View Slide

  21. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    CQRS (REQUEST HANDLING LAYER)
    21
    class GETRequestHandler
    {
    public function handle( $request, $session ) : void
    {
    $page = new TemplatePage('/newsletter-form');
    if ( $session->hasErrors() )
    {
    $page->addErrors( $session->getErrors() );
    }
    $page->display();
    }
    }

    View Slide

  22. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    22
    CQRS (REQUEST HANDLING LAYER)
    ๏ GET-REQUEST
    ๏ NO VIEW LOGIC
    ๏ COULD BE A STATIC

    HTML PAGE
    ๏ CAN BE DELETED 

    AFTER SUBSCRIPTION

    IS FINISHED

    View Slide

  23. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    CQRS (REQUEST HANDLING LAYER)
    23
    class POSTRequestHandler
    {
    public function handle( $request, $session ) : void
    {
    #... input validation passed ...
    $command = new InitSubscriptionCommand(
    new Fullname( $request->get( 'fullname' ) ),
    new Email( $request->get( 'email' ) )
    );
    $handler = new InitSubscriptionCommandHandler();
    $result = $handler->handle( $command );
    if ( $result->succeeded() )
    {
    # $publisher->publish( $result );
    (new Redirect())->respond(
    '/success-' . $result->getSubscription()->getId()
    );
    return;
    }
    }
    }

    View Slide

  24. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    CQRS (REQUEST HANDLING LAYER)
    24
    class InitSubscriptionResult
    {
    public function succeeded() : bool
    public function getErrors() : array
    public function getSubscription() : NewsletterSubscription
    }
    class Subscriber
    {
    public function notify( InitSubscriptionResult $result ) : void
    {
    $subscription = $result->getSubscription();
    $page = new TemplatePage('/newsletter-init-success');
    $page->assign( 'subscription', $subscription );
    $page->saveAsHTML( '/newsletter-' . $subscription->getId() );
    }
    }

    View Slide

  25. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    25
    CQRS (REQUEST HANDLING LAYER)
    ๏ E-MAIL
    ๏ CALL TO ACTION

    FOR A STATE CHANGE
    ๏ POST REQUESTS

    NOT AVAILABLE 

    FROM E-MAILS!

    View Slide

  26. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    26
    RESPECT HTTP VERBS!
    CQRS (REQUEST HANDLING LAYER)

    View Slide

  27. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    27
    […] the convention has been established
    that the GET and HEAD methods
    SHOULD NOT have the significance
    of taking an action other than retrieval.
    These methods ought
    to be considered "safe".
    https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
    CQRS (REQUEST HANDLING LAYER)

    View Slide

  28. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    28
    CQRS (REQUEST HANDLING LAYER)
    ๏ DON’T CHANGE STATE
    FROM GET REQUESTS!
    ๏ GET-REQUEST
    ๏ NO VIEW LOGIC
    ๏ COULD BE A STATIC

    HTML PAGE, PREPARED
    BASED ON SUCCESSFUL 

    INIT RESULT
    ๏ SUBMIT TRIGGERS 

    POST REQUEST
    ๏ CAN BE DELETED 

    AFTER SUBSCRIPTION

    IS FINISHED

    View Slide

  29. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    29
    CQRS (REQUEST HANDLING LAYER)
    ๏ GET-REQUEST

    AFTER REDIRECT
    ๏ NO VIEW LOGIC
    ๏ COULD BE A STATIC

    HTML PAGE, PREPARED
    BASED ON SUCCESSFUL 

    FINISH RESULT

    View Slide

  30. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    30
    BTW ;-)
    icehawk.github.io
    PHP7 micro framework - respecting CQRS

    View Slide

  31. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    31
    PERSISTENCE LAYER & STATE
    SubscriberID Fullname Email Interval Subscribed Confirmed Unsubscribed
    ‹UUID-HW›
    Holger
    Woltersdorf
    hollodotme
    @PHPkonf.org
    ONLY WHEN
    PHPkonf
    happens
    2017-05-19 2017-05-20 2017-05-21
    ‹UUID-JD› Jane Doe [email protected] Monthly 2017-03-01 NULL NULL
    SubscriberID Topic
    ‹UUID-HW› HIPSTER JEANS
    ‹UUID-HW› NERD CAPS
    ‹UUID-HW› MEME SHIRTS

    View Slide

  32. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    32
    PERSISTENCE LAYER & STATE
    WHAT HAPPENS, IF…
    I subscribe again
    for MEME SHIRTS only
    with WEEKLY interval

    View Slide

  33. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    33
    PERSISTENCE LAYER & STATE
    SubscriberID Fullname Email Interval Subscribed Confirmed Unsubscribed
    ‹UUID-HW›
    Holger
    Woltersdorf
    hollodotme
    @PHPkonf.org
    Weekly 2017-05-22 2017-05-23 NULL
    ‹UUID-JD› Jane Doe [email protected] Monthly 2017-03-01 NULL NULL
    SubscriberID Topic
    ‹UUID-HW› MEME SHIRTS

    View Slide

  34. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    34
    PERSISTENCE LAYER & STATE
    ‹‹ MY E-MAIL
    DUPLICATE CHECK
    WORKED OUT! ››
    DEVELOPER:
    YES!
    ADMIN:
    YES!
    ‹‹ YOU KEPT OUR
    DATABASE SLIGHT
    AND FAST! ››

    View Slide

  35. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    ‹‹ ARE YOU INSANE?
    YOU JUST ERASED
    VALUABLE B.I. DATA! ››
    35
    PERSISTENCE LAYER & STATE
    BUSINESS ANALYST:

    View Slide

  36. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    CQRS (PERSISTENCE LAYER - STATE)
    36
    What have we lost?
    ACTUALLY ALL INFORMATION
    ABOUT THE FIRST SUBSCRIPTION
    except e-mail & full name

    View Slide

  37. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    CQRS (PERSISTENCE LAYER - STATE)
    37
    What else have we lost?
    ANALYSABLE DATA
    ABOUT THE USER’S DECISION
    TO REACTIVATE AND CHANGE SUBSCRIPTION

    View Slide

  38. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    38
    CQRS (PERSISTENCE LAYER - STATE)
    The application state is observable,
    BUT ONLY AT THE EXACT POINT OF TIME
    we look at it.

    View Slide

  39. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    39
    + EVENT SOURCING

    View Slide

  40. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    EVENT SOURCING
    40
    ๏ EVENT SOURCING IS AN ANALYSIS PATTERN
    ๏ Article by Martin Fowler in 2005
    ๏ CQRS + Event Sourcing also part of Greg Young’s CQRS documents
    ๏ Pattern was already used in accounting software way earlier
    ๏ Key concept: 


    "Record all changes to application state as a sequence of events."

    — Martin Fowler
    GREG YOUNG
    MARTIN FOWLER

    View Slide

  41. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    41
    INSTALLING EVENT SOURCING
    READ REQUESTS
    BUSINESS LOGIC
    REPRESENTATION
    WRITE REQUESTS
    STATE
    PUBLISH SUBSCRIBE
    REDIRECT (+ SESSION)
    VIEW LOGIC

    View Slide

  42. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    42
    INSTALLING EVENT SOURCING
    READ REQUESTS
    BUSINESS LOGIC
    REPRESENTATION
    WRITE REQUESTS
    STATE
    PUBLISH SUBSCRIBE
    REDIRECT (+ SESSION)
    VIEW LOGIC

    View Slide

  43. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    43
    INSTALLING EVENT SOURCING
    READ REQUESTS
    BUSINESS LOGIC
    REPRESENTATION
    WRITE REQUESTS
    EVENT STORE
    PUBLISH SUBSCRIBE
    REDIRECT (+ SESSION)
    VIEW LOGIC
    READ HISTORY OF CHANGES
    RECORD NEW CHANGES

    View Slide

  44. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    EVENT SOURCING
    44
    BUSINESS ENTITY
    EVENTSTORE
    COMMAND
    TRIGGER CHANGES
    EMITS EVENTS
    (ALL NEW CHANGES)
    BUILT FROM
    EVENT STREAM
    (HISTORY OF CHANGES)
    PUBLISH NEWLY RECORDED EVENTS

    View Slide

  45. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    45
    EVENT STORE
    Seq StreamType StreamID StreamSeq EventID Payload Occurred MetaX Meta…
    10
    Newsletter

    Subscription
    ‹UUID-HW› 1
    Subscription was
    initiated
    {"json"}
    2017-05-21
    T12:13:14
    SHOP TY …
    11 Newsletter

    Subscription
    ‹UUID-HW› 2 Interval was
    changed
    {"json"} 2017-05-22
    T10:09:08
    SHOP TY …
    12 Newsletter

    Subscription
    ‹UUID-HW› 3 Topic was assigned {"json"} 2017-05-22
    T10:09:08
    SHOP TY …
    13 Newsletter
    Subscription
    ‹UUID-HW› 4 Topic was assigned {"json"} 2017-05-22
    T10:09:08
    SHOP TY …
    14 Newsletter

    Subscription
    ‹UUID-HW› 5 Topic was assigned {"json"} 2017-05-22
    T10:09:08
    SHOP TY …
    15 Newsletter

    Subscription
    ‹UUID-HW› 6 Subscription was
    confirmed
    {"json"} 2017-05-22
    T10:09:08
    SHOP TY …
    33 Newsletter

    Subscription
    ‹UUID-HW› 7 Subscription was
    canceled
    {"json"} 2017-05-25
    T07:09:09
    SHOP DE …
    50 Newsletter

    Subscription
    ‹UUID-HW› 8 Subscription was
    reactivated
    {"json"} 2017-06-01
    T14:15:16
    SHOP DE …
    51 Newsletter

    Subscription
    ‹UUID-HW› 9 Topic was removed {"json"} 2017-06-01
    T14:15:16
    SHOP DE …
    52 Newsletter
    Subscription
    ‹UUID-HW› 10 Topic was removed {"json"} 2017-06-01
    T14:15:16
    SHOP DE …
    53 Newsletter

    Subscription
    ‹UUID-HW› 11 Interval was
    changed
    {"json"} 2017-06-01
    T14:15:16
    SHOP DE …
    54 Newsletter

    Subscription
    ‹UUID-HW› 12 Subscription was
    confirmed
    {"json"} 2017-06-02
    T16:17:18
    SHOP DE …

    View Slide

  46. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    Seq StreamType StreamID StreamSeq EventID Payload Occurred MetaX Meta…
    10
    Newsletter

    Subscription
    ‹UUID-HW› 1
    Subscription was
    initiated
    {"json"}
    2017-05-21
    T12:13:14
    SHOP TY …
    11 Newsletter

    Subscription
    ‹UUID-HW› 2 Interval was
    changed
    {"json"} 2017-05-22
    T10:09:08
    SHOP TY …
    12 Newsletter

    Subscription
    ‹UUID-HW› 3 Topic was assigned {"json"} 2017-05-22
    T10:09:08
    SHOP TY …
    13 Newsletter
    Subscription
    ‹UUID-HW› 4 Topic was assigned {"json"} 2017-05-22
    T10:09:08
    SHOP TY …
    14 Newsletter

    Subscription
    ‹UUID-HW› 5 Topic was assigned {"json"} 2017-05-22
    T10:09:08
    SHOP TY …
    15 Newsletter

    Subscription
    ‹UUID-HW› 6 Subscription was
    confirmed
    {"json"} 2017-05-22
    T10:09:08
    SHOP TY …
    33 Newsletter

    Subscription
    ‹UUID-HW› 7 Subscription was
    canceled
    {"json"} 2017-05-25
    T07:09:09
    SHOP DE …
    50 Newsletter

    Subscription
    ‹UUID-HW› 8 Subscription was
    reactivated
    {"json"} 2017-06-01
    T14:15:16
    SHOP DE …
    51 Newsletter

    Subscription
    ‹UUID-HW› 9 Topic was removed {"json"} 2017-06-01
    T14:15:16
    SHOP DE …
    52 Newsletter
    Subscription
    ‹UUID-HW› 10 Topic was removed {"json"} 2017-06-01
    T14:15:16
    SHOP DE …
    53 Newsletter

    Subscription
    ‹UUID-HW› 11 Interval was
    changed
    {"json"} 2017-06-01
    T14:15:16
    SHOP DE …
    54 Newsletter

    Subscription
    ‹UUID-HW› 12 Subscription was
    confirmed
    {"json"} 2017-06-02
    T16:17:18
    SHOP DE …
    46
    EVENT STORE
    SEQUENCE SORTING ALL EVENTS IN THE EVENT STORE
    (AUTO-INCREMENT)

    View Slide

  47. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    Seq StreamType StreamID StreamSeq EventID Payload Occurred MetaX Meta…
    10
    Newsletter

    Subscription
    ‹UUID-HW› 1
    Subscription was
    initiated
    {"json"}
    2017-05-21
    T12:13:14
    SHOP TY …
    11 Newsletter

    Subscription
    ‹UUID-HW› 2 Interval was
    changed
    {"json"} 2017-05-22
    T10:09:08
    SHOP TY …
    12 Newsletter

    Subscription
    ‹UUID-HW› 3 Topic was assigned {"json"} 2017-05-22
    T10:09:08
    SHOP TY …
    13 Newsletter
    Subscription
    ‹UUID-HW› 4 Topic was assigned {"json"} 2017-05-22
    T10:09:08
    SHOP TY …
    14 Newsletter

    Subscription
    ‹UUID-HW› 5 Topic was assigned {"json"} 2017-05-22
    T10:09:08
    SHOP TY …
    15 Newsletter

    Subscription
    ‹UUID-HW› 6 Subscription was
    confirmed
    {"json"} 2017-05-22
    T10:09:08
    SHOP TY …
    33 Newsletter

    Subscription
    ‹UUID-HW› 7 Subscription was
    canceled
    {"json"} 2017-05-25
    T07:09:09
    SHOP DE …
    50 Newsletter

    Subscription
    ‹UUID-HW› 8 Subscription was
    reactivated
    {"json"} 2017-06-01
    T14:15:16
    SHOP DE …
    51 Newsletter

    Subscription
    ‹UUID-HW› 9 Topic was removed {"json"} 2017-06-01
    T14:15:16
    SHOP DE …
    52 Newsletter
    Subscription
    ‹UUID-HW› 10 Topic was removed {"json"} 2017-06-01
    T14:15:16
    SHOP DE …
    53 Newsletter

    Subscription
    ‹UUID-HW› 11 Interval was
    changed
    {"json"} 2017-06-01
    T14:15:16
    SHOP DE …
    54 Newsletter

    Subscription
    ‹UUID-HW› 12 Subscription was
    confirmed
    {"json"} 2017-06-02
    T16:17:18
    SHOP DE …
    47
    EVENT STORE
    StreamType
    NAME OF THE BUSINESS ENTITY
    StreamID
    UNIQUE ID OF SPECIFIC BUSINESS ENTITY
    StreamSeq
    VERSION OF THE SPECIFIC BUSINESS ENTITY INSTANCE
    (USED TO SORT THE ENTITY’S EVENT STREAM)

    View Slide

  48. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    Seq StreamType StreamID StreamSeq EventID Payload Occurred MetaX Meta…
    10
    Newsletter

    Subscription
    ‹UUID-HW› 1
    Subscription was
    initiated
    {"json"}
    2017-05-21
    T12:13:14
    SHOP TY …
    11 Newsletter

    Subscription
    ‹UUID-HW› 2 Interval was
    changed
    {"json"} 2017-05-22
    T10:09:08
    SHOP TY …
    12 Newsletter

    Subscription
    ‹UUID-HW› 3 Topic was assigned {"json"} 2017-05-22
    T10:09:08
    SHOP TY …
    13 Newsletter
    Subscription
    ‹UUID-HW› 4 Topic was assigned {"json"} 2017-05-22
    T10:09:08
    SHOP TY …
    14 Newsletter

    Subscription
    ‹UUID-HW› 5 Topic was assigned {"json"} 2017-05-22
    T10:09:08
    SHOP TY …
    15 Newsletter

    Subscription
    ‹UUID-HW› 6 Subscription was
    confirmed
    {"json"} 2017-05-22
    T10:09:08
    SHOP TY …
    33 Newsletter

    Subscription
    ‹UUID-HW› 7 Subscription was
    canceled
    {"json"} 2017-05-25
    T07:09:09
    SHOP DE …
    50 Newsletter

    Subscription
    ‹UUID-HW› 8 Subscription was
    reactivated
    {"json"} 2017-06-01
    T14:15:16
    SHOP DE …
    51 Newsletter

    Subscription
    ‹UUID-HW› 9 Topic was removed {"json"} 2017-06-01
    T14:15:16
    SHOP DE …
    52 Newsletter
    Subscription
    ‹UUID-HW› 10 Topic was removed {"json"} 2017-06-01
    T14:15:16
    SHOP DE …
    53 Newsletter

    Subscription
    ‹UUID-HW› 11 Interval was
    changed
    {"json"} 2017-06-01
    T14:15:16
    SHOP DE …
    54 Newsletter

    Subscription
    ‹UUID-HW› 12 Subscription was
    confirmed
    {"json"} 2017-06-02
    T16:17:18
    SHOP DE …
    48
    EVENT STORE
    EventID
    NAME OF THE CHANGE
    (USED TO IDENTIFY EVENT CLASS)
    Payload
    ALL RELEVANT DATA THAT IS NEEDED
    TO REPRODUCE THE CHANGE
    USE ONE TECHNOLOGY INDEPENDENT
    DATA FORMAT!
    Occurred
    TIMESTAMP WHEN THE CHANGE WAS
    RECORDED
    DO NOT USE THIS FOR SORTING
    EVENT STREAMS
    DO NOT RELY ON TIMESTAMPS!
    IT’S JUST META DATA

    View Slide

  49. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    Seq StreamType StreamID StreamSeq EventID Payload Occurred MetaX Meta…
    10
    Newsletter

    Subscription
    ‹UUID-HW› 1
    Subscription was
    initiated
    {"json"}
    2017-05-21
    T12:13:14
    SHOP TY …
    11 Newsletter

    Subscription
    ‹UUID-HW› 2 Interval was
    changed
    {"json"} 2017-05-22
    T10:09:08
    SHOP TY …
    12 Newsletter

    Subscription
    ‹UUID-HW› 3 Topic was assigned {"json"} 2017-05-22
    T10:09:08
    SHOP TY …
    13 Newsletter
    Subscription
    ‹UUID-HW› 4 Topic was assigned {"json"} 2017-05-22
    T10:09:08
    SHOP TY …
    14 Newsletter

    Subscription
    ‹UUID-HW› 5 Topic was assigned {"json"} 2017-05-22
    T10:09:08
    SHOP TY …
    15 Newsletter

    Subscription
    ‹UUID-HW› 6 Subscription was
    confirmed
    {"json"} 2017-05-22
    T10:09:08
    SHOP TY …
    33 Newsletter

    Subscription
    ‹UUID-HW› 7 Subscription was
    canceled
    {"json"} 2017-05-25
    T07:09:09
    SHOP DE …
    50 Newsletter

    Subscription
    ‹UUID-HW› 8 Subscription was
    reactivated
    {"json"} 2017-06-01
    T14:15:16
    SHOP DE …
    51 Newsletter

    Subscription
    ‹UUID-HW› 9 Topic was removed {"json"} 2017-06-01
    T14:15:16
    SHOP DE …
    52 Newsletter
    Subscription
    ‹UUID-HW› 10 Topic was removed {"json"} 2017-06-01
    T14:15:16
    SHOP DE …
    53 Newsletter

    Subscription
    ‹UUID-HW› 11 Interval was
    changed
    {"json"} 2017-06-01
    T14:15:16
    SHOP DE …
    54 Newsletter

    Subscription
    ‹UUID-HW› 12 Subscription was
    confirmed
    {"json"} 2017-06-02
    T16:17:18
    SHOP DE …
    49
    EVENT STORE
    ADDITIONAL META DATA
    BUSINESS IRRELEVANT
    DEPENDS ON YOUR DOMAIN
    AND INFRASTRUCTURE
    FOR EXAMPLE
    SHOP INSTANCE
    SERVER INSTANCE
    AUTH-USER (IF NOT BUSINESS RELEVANT)
    APPLICATION VERSION
    ETC.
    ADD WHATEVER YOU NEED

    View Slide

  50. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    Seq StreamType StreamID StreamSeq EventID Payload Occurred MetaX Meta…
    10
    Newsletter

    Subscription
    ‹UUID-HW› 1
    Subscription was
    initiated
    {"json"}
    2017-05-21
    T12:13:14
    SHOP TY …
    11 Newsletter

    Subscription
    ‹UUID-HW› 2 Interval was
    changed
    {"json"} 2017-05-22
    T10:09:08
    SHOP TY …
    12 Newsletter

    Subscription
    ‹UUID-HW› 3 Topic was assigned {"json"} 2017-05-22
    T10:09:08
    SHOP TY …
    13 Newsletter
    Subscription
    ‹UUID-HW› 4 Topic was assigned {"json"} 2017-05-22
    T10:09:08
    SHOP TY …
    14 Newsletter

    Subscription
    ‹UUID-HW› 5 Topic was assigned {"json"} 2017-05-22
    T10:09:08
    SHOP TY …
    15 Newsletter

    Subscription
    ‹UUID-HW› 6 Subscription was
    confirmed
    {"json"} 2017-05-22
    T10:09:08
    SHOP TY …
    33 Newsletter

    Subscription
    ‹UUID-HW› 7 Subscription was
    canceled
    {"json"} 2017-05-25
    T07:09:09
    SHOP DE …
    50 Newsletter

    Subscription
    ‹UUID-HW› 8 Subscription was
    reactivated
    {"json"} 2017-06-01
    T14:15:16
    SHOP DE …
    51 Newsletter

    Subscription
    ‹UUID-HW› 9 Topic was removed {"json"} 2017-06-01
    T14:15:16
    SHOP DE …
    52 Newsletter
    Subscription
    ‹UUID-HW› 10 Topic was removed {"json"} 2017-06-01
    T14:15:16
    SHOP DE …
    53 Newsletter

    Subscription
    ‹UUID-HW› 11 Interval was
    changed
    {"json"} 2017-06-01
    T14:15:16
    SHOP DE …
    54 Newsletter

    Subscription
    ‹UUID-HW› 12 Subscription was
    confirmed
    {"json"} 2017-06-02
    T16:17:18
    SHOP DE …
    50
    EVENT STORE
    FIRST SUBSCRIPTION
    PLEASE NOTE:
    GIVING BIRTH TO A NEW BUSINESS ENTITY
    IS A CHANGE TO APPLICATION STATE

    View Slide

  51. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    Seq StreamType StreamID StreamSeq EventID Payload Occurred MetaX Meta…
    10
    Newsletter

    Subscription
    ‹UUID-HW› 1
    Subscription was
    initiated
    {"json"}
    2017-05-21
    T12:13:14
    SHOP TY …
    11 Newsletter

    Subscription
    ‹UUID-HW› 2 Interval was
    changed
    {"json"} 2017-05-22
    T10:09:08
    SHOP TY …
    12 Newsletter

    Subscription
    ‹UUID-HW› 3 Topic was assigned {"json"} 2017-05-22
    T10:09:08
    SHOP TY …
    13 Newsletter
    Subscription
    ‹UUID-HW› 4 Topic was assigned {"json"} 2017-05-22
    T10:09:08
    SHOP TY …
    14 Newsletter

    Subscription
    ‹UUID-HW› 5 Topic was assigned {"json"} 2017-05-22
    T10:09:08
    SHOP TY …
    15 Newsletter

    Subscription
    ‹UUID-HW› 6 Subscription was
    confirmed
    {"json"} 2017-05-22
    T10:09:08
    SHOP TY …
    33 Newsletter

    Subscription
    ‹UUID-HW› 7 Subscription was
    canceled
    {"json"} 2017-05-25
    T07:09:09
    SHOP DE …
    50 Newsletter

    Subscription
    ‹UUID-HW› 8 Subscription was
    reactivated
    {"json"} 2017-06-01
    T14:15:16
    SHOP DE …
    51 Newsletter

    Subscription
    ‹UUID-HW› 9 Topic was removed {"json"} 2017-06-01
    T14:15:16
    SHOP DE …
    52 Newsletter
    Subscription
    ‹UUID-HW› 10 Topic was removed {"json"} 2017-06-01
    T14:15:16
    SHOP DE …
    53 Newsletter

    Subscription
    ‹UUID-HW› 11 Interval was
    changed
    {"json"} 2017-06-01
    T14:15:16
    SHOP DE …
    54 Newsletter

    Subscription
    ‹UUID-HW› 12 Subscription was
    confirmed
    {"json"} 2017-06-02
    T16:17:18
    SHOP DE …
    51
    EVENT STORE
    SECOND SUBSCRIPTION
    PLEASE NOTE:
    EXPRESS EXACTLY WHAT YOU ARE DOING
    INITIATED !== REACTIVATED
    AVOID AGGREGATION OF CHANGES
    YOU’LL LOSE VALUABLE INFORMATION
    Topics were changed !== Topic was added + Topic was removed

    View Slide

  52. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    EVENT STORE PAYLOAD
    52
    {
    "SubscriptionID": "‹UUID-HW›",
    "Fullname": "Holger Woltersdorf",
    "Email": "[email protected]"
    }
    "Subscription was initialised"
    {
    "SubscriptionID": "‹UUID-HW›"
    }
    vs.
    "Subscription was reactivated"

    View Slide

  53. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    EVENT STORE PAYLOAD
    53
    DO NOT ADD PREVIOUS VALUES TO PAYLOAD
    IT SHOULD HAVE BEEN RECORDED BEFORE
    STOP THINKING RELATIONAL
    START THINKING TEMPORAL

    View Slide

  54. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    EVENT SOURCING
    54
    interface EventInterface
    {
    public function getStreamID() : StreamIDInterface
    public function getEventID() : EventID
    public function getPayload() : Payload
    public static function fromPayload( Payload $payload ) : EventInterface
    }
    interface EventEnvelopeInterface
    {
    public function getHeader() : EventHeaderInterface
    public function getEvent() : EventInterface
    }

    View Slide

  55. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    EVENT SOURCING
    55
    interface EventHeaderInterface
    {
    public function getStreamType() : StreamType
    public function getStreamID() : StreamIDInterface
    public function getStreamSeq() : StreamSequence
    public function getOccurred() : Timestamp
    public function getMetaX() : ShopName
    public function getMeta…() : …
    }

    View Slide

  56. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    EVENT SOURCING
    56
    ๏ EVENT STORE IS IMMUTABLE AND APPEND-ONLY
    ๏ EVENT STORE IS THE ONLY SOURCE OF TRUTH
    ๏ USE TECHNOLOGY INDEPENDENT PAYLOAD FORMAT (XML/JSON/ETC.)

    DO NOT USE OBJECT SERIALISATION!
    ๏ EVENTS ARE IMMUTABLE
    ๏ SEPARATE PAYLOAD FROM META DATA (EVENT ENVELOPE)
    ๏ VALUE OBJECTS ARE IMMUTABLE
    ๏ EVENT STREAM IS A SORTED LIST OF EVENTS
    ๏ BUSINESS ENTITIES CAN NOT BE INSTANTIATED WITHOUT EVENT STREAM

    View Slide

  57. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    EVENT SOURCING (BUSINESS ENTITY)
    57
    class NewsletterSubscription
    {
    private $streamType;
    private $streamSeq;
    private $changes;
    # ...
    private function __construct()
    {
    $this->streamType = new StreamType( 'Newsletter Subscription' );
    $this->streamSeq = new StreamSeq( 0 );
    $this->changes = new EventStream();
    }
    # ...
    }

    View Slide

  58. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    EVENT SOURCING (BUSINESS ENTITY)
    58
    class NewsletterSubscription
    {
    public static function initiate(
    Email $email,
    Fullname $fullname
    ) : NewsletterSubscription
    {
    $subscription = new self();
    $subscription->recordThat(
    new SubscriptionWasInitiated(
    SubscriptionID::generate(),
    $email,
    $fullname
    )
    );
    return $subscription;
    }
    # ...
    }
    ๏ DO NOT CREATE ENTITIES
    WITHOUT RECORDING AN
    EVENT

    View Slide

  59. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    EVENT SOURCING (BUSINESS ENTITY)
    59
    class NewsletterSubscription
    {
    #...
    private function recordThat( EventInterface $event ) : void
    {
    $envelope = EnvelopeBuilder::build(
    $this->getStreamType(),
    $this->streamSeq->increment(),
    $event
    );
    $this->changes->append( $envelope );
    $this->apply( EventEnvelopeInterface $envelope );
    }
    #...
    }

    View Slide

  60. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    EVENT SOURCING (BUSINESS ENTITY)
    60
    class NewsletterSubscription
    {
    #...
    private function apply( EventEnvelopeInterface $envelope ) : void
    {
    $header = $envelope->getHeader();
    $event = $envelope->getEvent();
    $this->streamSeq = $header->getStreamSeq();
    $methodName = 'when' . $event->getEventID()->toUpperCamelCase();
    $this->$methodName( $event );
    # $this->whenSubscriptionWasInitiated( $event );
    }
    #...
    }

    View Slide

  61. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    EVENT SOURCING (BUSINESS ENTITY)
    61
    class NewsletterSubscription
    {
    #...
    protected function whenSubscriptionWasInitiated(
    SubscriptionWasInitiated $event
    ) : void
    {
    $this->email = $event->getEmail();
    $this->fullname = $event->getFullname();
    # This is your "real" constructor
    # Init properties here
    }
    #...
    }

    View Slide

  62. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    EVENT SOURCING (BUSINESS ENTITY)
    62
    class NewsletterSubscription
    {
    #...
    public static function reconstitute( EventStream $eventStream ) : self
    {
    $subscription = new self();
    foreach ( $eventStream as $envelope )
    {
    $subscription->apply( $envelope );
    }
    return $subscription;
    }
    #...
    }

    View Slide

  63. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    EVENT SOURCING (BUSINESS ENTITY)
    63
    abstract class AbstractBusinessEntity
    {
    final protected function __construct()
    final protected function recordThat( EventInterface $event ): void
    private function apply( EventEnvelopeInterface $envelope ) : void
    final public static function reconstitute( EventStream $eventStream )
    }

    View Slide

  64. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    EVENT SOURCING (BUSINESS ENTITY)
    64
    class NewsletterSubscription extends AbstractBusinessEntity
    {
    private $topics;
    public function assignTopic( Topic $topic ) : void
    protected function whenTopicWasAssigned( TopicWasAssigned $event ) : void
    }
    class NewsletterSubscription extends AbstractBusinessEntity
    {
    use NewsletterSubscriptionChanging;
    public function assignTopic( Topic $topic ) : void
    }
    USE A TRAIT TO EXPOSE PUBLIC API ONLY
    trait NewsletterSubscriptionChanging
    {
    private $topics;
    protected function whenTopicWasAssigned( TopicWasAssigned $event ) : void
    }

    View Slide

  65. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    EVENT SOURCING
    65
    ๏ QUESTIONS WE CAN ASK NOW:
    ๏ WHAT WAS THE (UN-)SUBSCRIBE RATIO IN 2016?
    ๏ HOW MANY USERS REACTIVATED THEIR SUBSCRIPTION IN 2017?
    ๏ HOW MANY USERS REACTIVATED MORE THAN ONCE?
    ๏ WHICH TOPIC WAS REMOVED THE MOST?
    ๏ HOW MANY USERS CHANGED INTERVAL BEFORE SUBSCRIPTION WAS CANCELED?

    View Slide

  66. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    66
    EVENT SOURCING
    READ REQUESTS
    BUSINESS LOGIC
    REPRESENTATION
    WRITE REQUESTS
    EVENT STORE
    PUBLISH SUBSCRIBE
    REDIRECT (+ SESSION)
    VIEW LOGIC
    READ HISTORY OF CHANGES
    RECORD NEW CHANGES

    View Slide

  67. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    RECORD NEW CHANGES
    READ HISTORY OF CHANGES
    67
    EVENT SOURCING
    READ REQUESTS
    BUSINESS LOGIC
    REPRESENTATION
    WRITE REQUESTS
    EVENT STORE
    PUBLISH SUBSCRIBE
    REDIRECT (+ SESSION)
    VIEW LOGIC

    View Slide

  68. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    RECORD NEW CHANGES
    READ HISTORY OF CHANGES
    68
    EVENT SOURCING (PROJECTION)
    READ REQUESTS
    BUSINESS LOGIC
    PROJECTION
    WRITE REQUESTS
    EVENT STORE
    PUBLISH SUBSCRIBE
    REDIRECT (+ SESSION)
    VIEW LOGIC

    View Slide

  69. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    RECORD NEW CHANGES
    READ HISTORY OF CHANGES
    69
    EVENT SOURCING (PROJECTION)
    READ REQUESTS
    BUSINESS LOGIC
    WRITE REQUESTS
    REDIRECT (+ SESSION)
    VIEW LOGIC
    REPRESENTATION
    REPRESENTATION
    EVENT STORE
    PUBLISH SUBSCRIBE
    PROJECTION
    MESSAGE
    BROKER
    ASYNC
    EVENTUAL
    CONSISTENCY
    !

    View Slide

  70. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    EVENT SOURCING (PROJECTING)
    70
    ๏ PUSH VIEWS
    ๏ Gets notified about a new change (event)
    ๏ Can directly project this information
    ๏ PULL VIEWS
    ๏ Gets a query and pulls up appropriate event streams to gather information
    ๏ Can respond or project the result
    ๏ MIXED VIEWS
    ๏ Gets notified and gathers missing information from event store
    ๏ Projects this information

    View Slide

  71. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    EVENT SOURCING (PROJECTING)
    71
    PLEASE NOTE:
    PROJECTIONS SHOULD CONVERT STATE INFORMATION
    TO THE BEST DATA FORMAT FOR YOUR READ-USE-CASE
    THIS COULD ALSO BE ANOTHER EVENT STORE
    WITH A SUBSET OF STREAMS / EVENTS

    View Slide

  72. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    CQRS ADVANTAGES
    72
    ๏ WHAT CAN WE GAIN FROM APPLYING CQRS?
    ๏ Separate input / output handling
    ๏ Opportunity to optimise each side for its operational purpose
    ๏ Depends on your application domain
    ๏ e.g. eCommerce Shops usually have a read / write ratio of 95% / 5%

    so optimisation for reading is a good idea
    ๏ Clean code, reusable queries and commands, decoupling, simpler tests
    ๏ No unintended side effects
    ๏ Technology independence for each side
    ๏ Good prerequisite for individual horizontal scalability

    View Slide

  73. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    EVENT SOURCING ADVANTAGES
    73
    ๏ WHAT CAN WE GAIN FROM USING EVENT SOURCING?
    ๏ High scalability
    ๏ Simplification of storing application state ("one size fits all")
    ๏ Traceability of all changes ever made to application state
    ๏ Retroactive data analysis at any time
    ๏ Adapting new business requirements with ease
    ๏ Restoring state representation at any given point in time
    ๏ Replay after bug fixes to reestablish view consistency
    ๏ Easy backup

    View Slide

  74. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    74
    QUESTIONS?

    View Slide

  75. THANK YOU!
    github.com/hollodotme
    @hollodotme / @F9T3ch
    fortuneglobe.com
    phpug-dresden.org
    @phpugdd
    HOLGER WOLTERSDORF
    icehawk.github.io
    speakerdeck.com/hollodotme
    Slides available at:

    View Slide

  76. TOTAL RECALL - THE APPLICATION THAT NEVER FORGETS • MAY 20th 2017 • PHPkonf. • ISTANBUL HOLGER WOLTERSDORF
    LINKS / REFERENCES
    76
    ๏ CQS:
    ๏ https://martinfowler.com/bliki/CommandQuerySeparation.html
    ๏ https://en.wikipedia.org/wiki/Command%E2%80%93query_separation
    ๏ Bertrand Meyer:
    ๏ https://de.wikipedia.org/wiki/Bertrand_Meyer
    ๏ https://bertrandmeyer.com
    ๏ Book "Object-Oriented Software Construction 2Ed" by Bertrand Meyer: http://amzn.to/2qdnc2i
    ๏ Greg Young’s CQRS documents: https://cqrs.files.wordpress.com/2010/11/cqrs_documents.pdf
    ๏ GET/HEAD methods: https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
    ๏ Article about Event Sourcing by Martin Fowler: https://martinfowler.com/eaaDev/EventSourcing.html
    ๏ PHP FastCGI Client: https://github.com/hollodotme/fast-cgi-client
    ๏ IceHawk micro framework: https://icehawk.github.io

    View Slide