Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Let's write some history - PHPDay 2016

Let's write some history - PHPDay 2016

Did you know that you are probably throwing away data every single day? By updating or deleting records from your database you lose information. In this talk I’m going to explain how Event Sourcing can help you solve this problem and what other benefits you can get from it. We will walk over of the concepts and possible implementations of event sourcing with examples from Qandidate.com.

Willem-Jan Zijderveld

May 14, 2016
Tweet

More Decks by Willem-Jan Zijderveld

Other Decks in Programming

Transcript

  1. 1/101
    Event Sourcing
    Let's write some history
    https://joind.in/talk/3375d

    View full-size slide

  2. Willem-Jan Zijderveld
    @willemjanz
    github.com/wjzijderveld


    View full-size slide

  3. Rotterdam
    http://labs.qandidate.com

    View full-size slide

  4. Broadway
    Event Sourcing/CQRS
    library for PHP
    github.com/qandidate-labs/broadway

    View full-size slide

  5. Event Sourcing

    View full-size slide

  6. You are throwing away data!

    View full-size slide

  7. Only state gets
    stored

    View full-size slide

  8. Only the most
    recent state
    gets stored

    View full-size slide

  9. What was the previous
    state?

    View full-size slide

  10. Why did the state change?

    View full-size slide

  11. It's hard to keep track of
    all the data

    View full-size slide

  12. A company has one or
    more connected accounts

    View full-size slide

  13. A company has one or
    more enabled applications

    View full-size slide

  14. An account has access to
    one or more applications

    View full-size slide

  15. Complicated solutions to store and
    retrieve the data

    View full-size slide

  16. But we manage
    Until...

    View full-size slide

  17. Boss: Which accounts
    received access to
    application X in
    December?

    View full-size slide

  18. "We'll add a timestamp
    and we will know"
    From that point in time

    View full-size slide

  19. With CRUD you lose
    information
    You only store the last known information

    View full-size slide

  20. Another example

    View full-size slide

  21. Revoking access to an application for
    an account
    Just remove the row in our join table

    View full-size slide

  22. You lose when the access was
    revoked

    View full-size slide

  23. You lose why it got revoked

    View full-size slide

  24. You lose for which application it was
    revoked

    View full-size slide

  25. You wouldn't know anything anymore

    View full-size slide

  26. Let's assume you have
    a soft-delete in place

    View full-size slide

  27. Boss: I want to know for which
    applications access got revoked more
    than once
    in the last year

    View full-size slide

  28. Keep track of revocations
    account_id app_id datetime
    75623 8 2015-01-01T00:00:00+0000
    75623 8 2015-01-27T18:54:18+0000
    Are you going to do this for all actions on accounts?

    View full-size slide

  29. How does Event Sourcing
    help me with that?

    View full-size slide

  30. Store your data in
    a di erent way

    View full-size slide

  31. Record what has happened
    The resulting state becomes a natural effect

    View full-size slide

  32. A serie of facts
    CompanyRegistered
    AppEnabled
    AccountConnected
    AccessGrantedToApp

    View full-size slide

  33. Been there, done that

    View full-size slide

  34. Single source of truth
    One source to rule all state
    The events cannot lie, it happened, deal with it

    View full-size slide

  35. You have been working with this
    system

    View full-size slide

  36. Your version control is
    event sourced

    View full-size slide

  37. Sure thing, but how?
    "It depends"

    View full-size slide

  38. Event Sourcing
    DDD
    CQRS
    All 3 are optional, but work very nice together

    View full-size slide

  39. Domain Driven Design
    Let the events tell the story
    The business should be re ected in your code

    View full-size slide

  40. Entity
    An model with an identity

    View full-size slide

  41. Aggregate root
    Responsible for keeping a group of entities consistent

    View full-size slide

  42. I want to create/update
    my model
    How do I do that?

    View full-size slide

  43. Record what happened

    View full-size slide

  44. You normally might do it like this
    <
    ?
    p
    h
    p /
    / C
    o
    m
    p
    a
    n
    y
    .
    p
    h
    p
    p
    u
    b
    l
    i
    c f
    u
    n
    c
    t
    i
    o
    n _
    _
    c
    o
    n
    s
    t
    r
    u
    c
    t
    (
    $
    i
    d
    , $
    n
    a
    m
    e
    )
    {
    $
    t
    h
    i
    s
    -
    >
    i
    d = $
    i
    d
    ;
    $
    t
    h
    i
    s
    -
    >
    n
    a
    m
    e = $
    n
    a
    m
    e
    ;
    }

    View full-size slide

  45. But we want to record an
    event

    View full-size slide

  46. <
    ?
    p
    h
    p /
    / C
    o
    m
    p
    a
    n
    y
    .
    p
    h
    p
    p
    u
    b
    l
    i
    c s
    t
    a
    t
    i
    c f
    u
    n
    c
    t
    i
    o
    n r
    e
    g
    i
    s
    t
    e
    r
    (
    $
    i
    d
    , $
    n
    a
    m
    e
    )
    {
    $
    c
    o
    m
    p
    a
    n
    y = n
    e
    w C
    o
    m
    p
    a
    n
    y
    (
    )
    ;
    $
    c
    o
    m
    p
    a
    n
    y
    -
    >
    a
    p
    p
    l
    y
    (
    n
    e
    w C
    o
    m
    p
    a
    n
    y
    R
    e
    g
    i
    s
    t
    e
    r
    e
    d
    E
    v
    e
    n
    t
    (
    $
    i
    d
    , $
    n
    a
    m
    e
    )
    )
    ;
    r
    e
    t
    u
    r
    n $
    c
    o
    m
    p
    a
    n
    y
    ;
    }

    View full-size slide

  47. Record the events
    <
    p
    h
    p /
    / A
    g
    g
    r
    e
    g
    a
    t
    e
    R
    o
    o
    t
    .
    p
    h
    p
    p
    u
    b
    l
    i
    c f
    u
    n
    c
    t
    i
    o
    n a
    p
    p
    l
    y
    (
    $
    e
    v
    e
    n
    t
    )
    {
    $
    t
    h
    i
    s
    -
    >
    h
    a
    n
    d
    l
    e
    (
    $
    e
    v
    e
    n
    t
    )
    ;
    $
    t
    h
    i
    s
    -
    >
    u
    n
    c
    o
    m
    m
    i
    t
    e
    d
    E
    v
    e
    n
    t
    s
    [
    ] = $
    e
    v
    e
    n
    t
    ;
    }
    p
    r
    i
    v
    a
    t
    e f
    u
    n
    c
    t
    i
    o
    n h
    a
    n
    d
    l
    e
    (
    $
    e
    v
    e
    n
    t
    )
    {
    $
    c
    l
    a
    s
    s
    P
    a
    r
    t
    s = e
    x
    p
    l
    o
    d
    e
    (
    '
    \
    \
    '
    , $
    e
    v
    e
    n
    t
    )
    ;
    $
    m
    e
    t
    h
    o
    d = '
    a
    p
    p
    l
    y
    ' . e
    n
    d
    (
    $
    c
    l
    a
    s
    s
    P
    a
    r
    t
    s
    )
    ;
    $
    t
    h
    i
    s
    -
    >
    $
    m
    e
    t
    h
    o
    d
    (
    $
    e
    v
    e
    n
    t
    )
    ;
    }

    View full-size slide

  48. /
    / C
    o
    m
    p
    a
    n
    y
    .
    p
    h
    p
    p
    u
    b
    l
    i
    c f
    u
    n
    c
    t
    i
    o
    n a
    p
    p
    l
    y
    C
    o
    m
    p
    a
    n
    y
    R
    e
    g
    i
    s
    t
    e
    r
    e
    d
    E
    v
    e
    n
    t
    (
    C
    o
    m
    p
    a
    n
    y
    R
    e
    g
    i
    s
    t
    e
    r
    e
    d
    E
    v
    e
    n
    t $
    e
    v
    e
    n
    t
    ) {
    $
    t
    h
    i
    s
    -
    >
    c
    o
    m
    p
    a
    n
    y
    I
    d = $
    e
    v
    e
    n
    t
    -
    >
    g
    e
    t
    C
    o
    m
    p
    a
    n
    y
    I
    d
    (
    )
    ;
    $
    t
    h
    i
    s
    -
    >
    c
    o
    m
    p
    a
    n
    y
    N
    a
    m
    e = $
    e
    v
    e
    n
    t
    -
    >
    g
    e
    t
    C
    o
    m
    p
    a
    n
    y
    N
    a
    m
    e
    (
    )
    ;
    }

    View full-size slide

  49. Save your events in an
    eventstore

    View full-size slide

  50. Current situation

    View full-size slide

  51. Reloading your model

    View full-size slide

  52. <
    p
    h
    p /
    / C
    o
    m
    p
    a
    n
    y
    R
    e
    p
    o
    s
    i
    t
    o
    r
    y
    .
    p
    h
    p
    f
    u
    n
    c
    t
    i
    o
    n l
    o
    a
    d
    (
    $
    a
    g
    g
    r
    e
    g
    a
    t
    e
    I
    d
    )
    {
    $
    e
    v
    e
    n
    t
    s = $
    t
    h
    i
    s
    -
    >
    e
    v
    e
    n
    t
    S
    t
    o
    r
    e
    -
    >
    l
    o
    a
    d
    (
    $
    a
    g
    g
    r
    e
    g
    a
    t
    e
    I
    d
    )
    ;
    $
    a
    g
    g
    r
    e
    g
    a
    t
    e = n
    e
    w $
    t
    h
    i
    s
    -
    >
    a
    g
    g
    r
    e
    g
    a
    t
    e
    C
    l
    a
    s
    s
    (
    )
    ;
    $
    a
    g
    g
    r
    e
    g
    a
    t
    e
    -
    >
    i
    n
    i
    t
    i
    a
    l
    i
    z
    e
    S
    t
    a
    t
    e
    (
    $
    e
    v
    e
    n
    t
    s
    )
    ;
    r
    e
    t
    u
    r
    n $
    a
    g
    g
    r
    e
    g
    a
    t
    e
    ;
    }

    View full-size slide

  53. <
    ?
    p
    h
    p /
    / C
    o
    m
    p
    a
    n
    y
    .
    p
    h
    p
    p
    u
    b
    l
    i
    c f
    u
    n
    c
    t
    i
    o
    n i
    n
    i
    t
    i
    a
    l
    i
    z
    e
    S
    t
    a
    t
    e
    (
    a
    r
    r
    a
    y $
    e
    v
    e
    n
    t
    s
    )
    {
    f
    o
    r
    e
    a
    c
    h (
    $
    e
    v
    e
    n
    t
    s a
    s $
    e
    v
    e
    n
    t
    )
    {
    $
    t
    h
    i
    s
    -
    >
    h
    a
    n
    d
    l
    e
    (
    $
    e
    v
    e
    n
    t
    )
    ;
    }
    }

    View full-size slide

  54. Domain Message
    A message to tell your application what happened

    View full-size slide

  55. DomainMessage
    Identi er
    Sequencenumber
    Payload
    Timestamp
    Metadata

    View full-size slide

  56. Identi er + sequence
    number

    View full-size slide

  57. Payload
    The event itself, it tells you what
    happened

    View full-size slide

  58. Should contain everything
    It should only depend on previous events
    f
    i
    n
    a
    l c
    l
    a
    s
    s C
    o
    m
    p
    a
    n
    y
    R
    e
    g
    i
    s
    t
    e
    r
    e
    d
    E
    v
    e
    n
    t
    {
    p
    r
    i
    v
    a
    t
    e $
    c
    o
    m
    p
    a
    n
    y
    I
    d
    ;
    p
    r
    i
    v
    a
    t
    e $
    c
    o
    m
    p
    a
    n
    y
    N
    a
    m
    e
    ;
    /
    / c
    o
    n
    s
    t
    r
    u
    c
    t
    o
    r + g
    e
    t
    t
    e
    r
    s
    }

    View full-size slide

  59. Timestamp
    It tells you when it happened

    View full-size slide

  60. Metadata
    Descriptive, not structural

    View full-size slide

  61. Let's look at some other
    events
    CompanyRegistered
    AppEnabled
    AccountConnected
    AccessGrantedToApp

    View full-size slide

  62. CompanyRegistered
    /
    / C
    o
    m
    p
    a
    n
    y
    f
    u
    n
    c
    t
    i
    o
    n a
    p
    p
    l
    y
    C
    o
    m
    p
    a
    n
    y
    R
    e
    g
    i
    s
    t
    e
    r
    e
    d
    E
    v
    e
    n
    t
    (
    C
    o
    m
    p
    a
    n
    y
    R
    e
    g
    i
    s
    t
    e
    r
    e
    d
    E
    v
    e
    n
    t $
    e
    v
    e
    n
    t
    )
    {
    $
    t
    h
    i
    s
    -
    >
    c
    o
    m
    p
    a
    n
    y
    I
    d = $
    e
    v
    e
    n
    t
    -
    >
    g
    e
    t
    C
    o
    m
    p
    a
    n
    y
    I
    d
    (
    )
    ;
    }

    View full-size slide

  63. AccountConnected
    /
    / C
    o
    m
    p
    a
    n
    y
    f
    u
    n
    c
    t
    i
    o
    n a
    p
    p
    l
    y
    A
    c
    c
    o
    u
    n
    t
    C
    o
    n
    n
    e
    c
    t
    e
    d
    E
    v
    e
    n
    t
    (
    A
    c
    c
    o
    u
    n
    t
    C
    o
    n
    n
    e
    c
    t
    e
    d
    E
    v
    e
    n
    t $
    e
    v
    e
    n
    t
    )
    {
    $
    i
    d = $
    e
    v
    e
    n
    t
    -
    >
    g
    e
    t
    A
    c
    c
    o
    u
    n
    t
    I
    d
    (
    )
    ;
    $
    t
    h
    i
    s
    -
    >
    a
    c
    c
    o
    u
    n
    t
    s
    [
    $
    i
    d
    ] = $
    i
    d
    ;
    }

    View full-size slide

  64. AppEnabled
    /
    / C
    o
    m
    p
    a
    n
    y
    f
    u
    n
    c
    t
    i
    o
    n a
    p
    p
    l
    y
    A
    p
    p
    E
    n
    a
    b
    l
    e
    d
    E
    v
    e
    n
    t
    (
    A
    p
    p
    E
    n
    a
    b
    l
    e
    d
    E
    v
    e
    n
    t $
    e
    v
    e
    n
    t
    )
    {
    $
    s
    u
    b
    s
    c
    r
    i
    p
    t
    i
    o
    n = n
    e
    w S
    u
    b
    s
    c
    r
    i
    p
    t
    i
    o
    n
    (
    $
    e
    v
    e
    n
    t
    -
    >
    g
    e
    t
    C
    o
    m
    p
    a
    n
    y
    I
    d
    (
    )
    ,
    $
    e
    v
    e
    n
    t
    -
    >
    g
    e
    t
    A
    p
    p
    I
    d
    (
    )
    )
    ;
    $
    t
    h
    i
    s
    -
    >
    s
    u
    b
    s
    c
    r
    i
    p
    t
    i
    o
    n
    s
    [
    $
    e
    v
    e
    n
    t
    -
    >
    g
    e
    t
    A
    p
    p
    I
    d
    (
    )
    ] = $
    s
    u
    b
    s
    c
    r
    i
    p
    t
    i
    o
    n
    ;
    }

    View full-size slide

  65. AccessGrantedToApp
    /
    / C
    o
    m
    p
    a
    n
    y
    p
    r
    o
    t
    e
    c
    t
    e
    d f
    u
    n
    c
    t
    i
    o
    n g
    e
    t
    C
    h
    i
    l
    d
    E
    n
    t
    i
    t
    i
    e
    s
    (
    )
    {
    r
    e
    t
    u
    r
    n $
    t
    h
    i
    s
    -
    >
    s
    u
    b
    s
    c
    r
    i
    p
    t
    i
    o
    n
    s
    ;
    }
    /
    / S
    u
    b
    s
    c
    r
    i
    p
    t
    i
    o
    n
    f
    u
    n
    c
    t
    i
    o
    n a
    p
    p
    l
    y
    A
    c
    c
    e
    s
    s
    G
    r
    a
    n
    t
    e
    d
    T
    o
    A
    p
    p
    E
    v
    e
    n
    t
    (
    A
    c
    c
    e
    s
    s
    G
    r
    a
    n
    t
    e
    d
    T
    o
    A
    p
    p
    E
    v
    e
    n
    t $
    e
    v
    e
    n
    t
    ) {
    i
    f (
    $
    t
    h
    i
    s
    -
    >
    a
    p
    p
    I
    d !
    =
    = $
    e
    v
    e
    n
    t
    -
    >
    g
    e
    t
    A
    p
    p
    I
    d
    (
    )
    ) {
    r
    e
    t
    u
    r
    n
    ;
    }
    $
    a
    c
    c
    o
    u
    n
    t
    I
    d = $
    e
    v
    e
    n
    t
    -
    >
    g
    e
    t
    A
    c
    c
    o
    u
    n
    t
    I
    d
    (
    )
    ;
    $
    t
    h
    i
    s
    -
    >
    g
    r
    a
    n
    t
    e
    d
    A
    c
    c
    o
    u
    n
    t
    s
    [
    $
    a
    c
    c
    o
    u
    n
    t
    I
    d
    ] = $
    a
    c
    c
    o
    u
    n
    t
    I
    d
    ;
    }

    View full-size slide

  66. We can retrieve all
    AccessGranted events for
    December

    View full-size slide

  67. Won't this be slow?

    View full-size slide

  68. CQRS
    Command Query Responsibility Segregation

    View full-size slide

  69. Separate your writes and
    your reads

    View full-size slide

  70. Read Models
    Create them from events using projections
    Speci c read models for speci c views in your application

    View full-size slide

  71. EventBus
    All events go onto the event bus after being saved

    View full-size slide

  72. CompanyRegistration
    c
    l
    a
    s
    s C
    o
    m
    p
    a
    n
    y
    R
    e
    g
    i
    s
    t
    r
    a
    t
    i
    o
    n i
    m
    p
    l
    e
    m
    e
    n
    t
    s R
    e
    a
    d
    M
    o
    d
    e
    l
    {
    p
    u
    b
    l
    i
    c f
    u
    n
    c
    t
    i
    o
    n _
    _
    c
    o
    n
    s
    t
    r
    u
    c
    t
    (
    $
    c
    o
    m
    p
    a
    n
    y
    I
    d
    ,
    $
    c
    o
    m
    p
    a
    n
    y
    N
    a
    m
    e
    ,
    D
    a
    t
    e
    T
    i
    m
    e $
    r
    e
    g
    i
    s
    t
    e
    r
    e
    d
    O
    n
    ) {
    /
    / .
    .
    }
    }

    View full-size slide

  73. Company Registration Projector
    c
    l
    a
    s
    s C
    o
    m
    p
    a
    n
    y
    R
    e
    g
    i
    s
    t
    r
    a
    t
    i
    o
    n
    P
    r
    o
    j
    e
    c
    t
    o
    r i
    m
    p
    l
    e
    m
    e
    n
    t
    s E
    v
    e
    n
    t
    L
    i
    s
    t
    e
    n
    e
    r
    {
    p
    u
    b
    l
    i
    c f
    u
    n
    c
    t
    i
    o
    n a
    p
    p
    l
    y
    C
    o
    m
    p
    a
    n
    y
    R
    e
    g
    i
    s
    t
    e
    r
    e
    d
    E
    v
    e
    n
    t
    (
    C
    o
    m
    p
    a
    n
    y
    R
    e
    g
    i
    s
    t
    e
    r
    e
    d
    E
    v
    e
    n
    t $
    e
    v
    e
    n
    t
    ,
    D
    o
    m
    a
    i
    n
    M
    e
    s
    s
    a
    g
    e $
    d
    o
    m
    a
    i
    n
    M
    e
    s
    s
    a
    g
    e
    ) {
    $
    c
    o
    m
    p
    a
    n
    y = n
    e
    w C
    o
    m
    p
    a
    n
    y
    R
    e
    g
    i
    s
    t
    r
    a
    t
    i
    o
    n
    (
    $
    e
    v
    e
    n
    t
    -
    >
    g
    e
    t
    C
    o
    m
    p
    a
    n
    y
    I
    d
    (
    )
    ,
    $
    e
    v
    e
    n
    t
    -
    >
    g
    e
    t
    C
    o
    m
    p
    a
    n
    y
    N
    a
    m
    e
    (
    )
    ,
    $
    d
    o
    m
    a
    i
    n
    M
    e
    s
    s
    a
    g
    e
    -
    >
    g
    e
    t
    R
    e
    c
    o
    r
    d
    e
    d
    O
    n
    (
    )
    )
    ;
    $
    t
    h
    i
    s
    -
    >
    r
    e
    p
    o
    s
    i
    t
    o
    r
    y
    -
    >
    s
    a
    v
    e
    (
    $
    c
    o
    m
    p
    a
    n
    y
    )
    ;
    }
    }

    View full-size slide

  74. Use the right tool for the
    right job

    View full-size slide

  75. Possibilities are endless

    View full-size slide

  76. The ability to create multiple read
    models
    List of company registrations
    Graph of all connections between companies and accounts
    Creating reports about the amount of revocations

    View full-size slide

  77. So.. how does this ow
    work in an application?

    View full-size slide

  78. The C in CQRS

    View full-size slide

  79. The write part of CQRS

    View full-size slide

  80. Command & CommandHandler
    A CommandHandler deals with Commands and communicates
    with the Aggregate root

    View full-size slide

  81. From Controller
    to CommandBus
    c
    l
    a
    s
    s C
    o
    m
    p
    a
    n
    y
    C
    o
    n
    t
    r
    o
    l
    l
    e
    r
    {
    f
    u
    n
    c
    t
    i
    o
    n r
    e
    g
    i
    s
    t
    e
    r
    A
    c
    t
    i
    o
    n
    (
    R
    e
    q
    u
    e
    s
    t $
    r
    e
    q
    u
    e
    s
    t
    )
    {
    $
    t
    h
    i
    s
    -
    >
    c
    o
    m
    m
    a
    n
    d
    B
    u
    s
    -
    >
    d
    i
    s
    p
    a
    t
    c
    h
    (
    n
    e
    w R
    e
    g
    i
    s
    t
    e
    r
    C
    o
    m
    p
    a
    n
    y
    C
    o
    m
    m
    a
    n
    d
    (
    U
    u
    i
    d
    :
    :
    u
    u
    i
    d
    4
    (
    )
    ,
    $
    r
    e
    q
    u
    e
    s
    t
    -
    >
    r
    e
    q
    u
    e
    s
    t
    -
    >
    g
    e
    t
    (
    '
    c
    o
    m
    p
    a
    n
    y
    N
    a
    m
    e
    '
    )
    )
    )
    ;
    }
    }

    View full-size slide

  82. From CommandHandler
    to Aggregate
    c
    l
    a
    s
    s C
    o
    m
    p
    a
    n
    y
    C
    o
    m
    m
    a
    n
    d
    H
    a
    n
    d
    l
    e
    r
    {
    f
    u
    n
    c
    t
    i
    o
    n h
    a
    n
    d
    l
    e
    R
    e
    g
    i
    s
    t
    e
    r
    C
    o
    m
    p
    a
    n
    y
    C
    o
    m
    m
    a
    n
    d
    (
    R
    e
    g
    i
    s
    t
    e
    r
    C
    o
    m
    p
    a
    n
    y
    C
    o
    m
    m
    a
    n
    d $
    c
    o
    m
    m
    a
    n
    d
    ) {
    $
    c
    o
    m
    p
    a
    n
    y = C
    o
    m
    p
    a
    n
    y
    :
    :
    r
    e
    g
    i
    s
    t
    e
    r
    (
    $
    c
    o
    m
    m
    a
    n
    d
    -
    >
    g
    e
    t
    C
    o
    m
    p
    a
    n
    y
    I
    d
    (
    )
    ,
    $
    c
    o
    m
    m
    a
    n
    d
    -
    >
    g
    e
    t
    C
    o
    m
    p
    a
    n
    y
    N
    a
    m
    e
    (
    )
    )
    ;
    $
    t
    h
    i
    s
    -
    >
    a
    g
    g
    r
    e
    g
    a
    t
    e
    R
    e
    p
    o
    s
    t
    i
    t
    o
    r
    y
    -
    >
    s
    a
    v
    e
    (
    $
    c
    o
    m
    p
    a
    n
    y
    )
    ;
    }
    }

    View full-size slide

  83. From Aggregate to Event
    p
    u
    b
    l
    i
    c s
    t
    a
    t
    i
    c f
    u
    n
    c
    t
    i
    o
    n r
    e
    g
    i
    s
    t
    e
    r
    (
    $
    c
    o
    m
    p
    a
    n
    y
    I
    d
    , $
    n
    a
    m
    e
    )
    {
    $
    c
    o
    m
    p
    a
    n
    y = n
    e
    w C
    o
    m
    p
    a
    n
    y
    (
    )
    ;
    $
    c
    o
    m
    p
    a
    n
    y
    -
    >
    a
    p
    p
    l
    y
    (
    n
    e
    w C
    o
    m
    p
    a
    n
    y
    R
    e
    g
    i
    s
    t
    e
    r
    e
    d
    E
    v
    e
    n
    t
    (
    $
    c
    o
    m
    p
    a
    n
    y
    I
    d
    , $
    n
    a
    m
    e
    )
    )
    ;
    r
    e
    t
    u
    r
    n $
    c
    o
    m
    p
    a
    n
    y
    ;
    }
    p
    u
    b
    l
    i
    c f
    u
    n
    c
    t
    i
    o
    n a
    p
    p
    l
    y
    C
    o
    m
    p
    a
    n
    y
    R
    e
    g
    i
    s
    t
    e
    r
    e
    d
    E
    v
    e
    n
    t
    (
    C
    o
    m
    p
    a
    n
    y
    R
    e
    g
    i
    s
    t
    e
    r
    e
    d
    E
    v
    e
    n
    t $
    e
    v
    e
    n
    t
    ) {
    $
    t
    h
    i
    s
    -
    >
    c
    o
    m
    p
    a
    n
    y
    I
    d = $
    e
    v
    e
    n
    t
    -
    >
    g
    e
    t
    C
    o
    m
    p
    a
    n
    y
    I
    d
    (
    )
    ;
    }

    View full-size slide

  84. From Repository to EventStore
    /
    / C
    o
    m
    p
    a
    n
    y
    R
    e
    g
    i
    s
    t
    r
    y
    .
    p
    h
    p
    f
    u
    n
    c
    t
    i
    o
    n s
    a
    v
    e
    (
    $
    a
    g
    g
    r
    e
    g
    a
    t
    e
    )
    {
    $
    e
    v
    e
    n
    t
    s = $
    a
    g
    g
    r
    e
    g
    a
    t
    e
    -
    >
    g
    e
    t
    U
    n
    c
    o
    m
    m
    i
    t
    t
    e
    d
    E
    v
    e
    n
    t
    s
    (
    )
    ;
    $
    t
    h
    i
    s
    -
    >
    e
    v
    e
    n
    t
    S
    t
    o
    r
    e
    -
    >
    a
    p
    p
    e
    n
    d
    (
    $
    a
    g
    g
    r
    e
    g
    a
    t
    e
    -
    >
    g
    e
    t
    A
    g
    g
    r
    e
    g
    a
    t
    e
    I
    d
    (
    )
    , $
    e
    v
    e
    n
    t
    s
    )
    ;
    $
    t
    h
    i
    s
    -
    >
    e
    v
    e
    n
    t
    B
    u
    s
    -
    >
    p
    u
    b
    l
    i
    s
    h
    (
    $
    e
    v
    e
    n
    t
    s
    )
    ;
    }

    View full-size slide

  85. From event to read model
    c
    l
    a
    s
    s C
    o
    m
    p
    a
    n
    y
    R
    e
    g
    i
    s
    t
    r
    a
    t
    i
    o
    n
    P
    r
    o
    j
    e
    c
    t
    o
    r {
    p
    u
    b
    l
    i
    c f
    u
    n
    c
    t
    i
    o
    n a
    p
    p
    l
    y
    C
    o
    m
    p
    a
    n
    y
    R
    e
    g
    i
    s
    t
    e
    r
    e
    d
    E
    v
    e
    n
    t
    (
    C
    o
    m
    p
    a
    n
    y
    R
    e
    g
    i
    s
    t
    e
    r
    e
    d
    E
    v
    e
    n
    t $
    e
    v
    e
    n
    t
    ,
    D
    o
    m
    a
    i
    n
    M
    e
    s
    s
    a
    g
    e $
    d
    o
    m
    a
    i
    n
    M
    e
    s
    s
    a
    g
    e
    ) {
    $
    c
    o
    m
    p
    a
    n
    y = n
    e
    w C
    o
    m
    p
    a
    n
    y
    R
    e
    g
    i
    s
    t
    r
    a
    t
    i
    o
    n
    (
    $
    e
    v
    e
    n
    t
    -
    >
    g
    e
    t
    C
    o
    m
    p
    a
    n
    y
    I
    d
    (
    )
    ,
    $
    e
    v
    e
    n
    t
    -
    >
    g
    e
    t
    C
    o
    m
    p
    a
    n
    y
    N
    a
    m
    e
    (
    )
    ,
    $
    d
    o
    m
    a
    i
    n
    M
    e
    s
    s
    a
    g
    e
    -
    >
    g
    e
    t
    R
    e
    c
    o
    r
    d
    e
    d
    O
    n
    (
    )
    )
    ;
    $
    t
    h
    i
    s
    -
    >
    r
    e
    p
    o
    s
    i
    t
    o
    r
    y
    -
    >
    s
    a
    v
    e
    (
    $
    c
    o
    m
    p
    a
    n
    y
    )
    ;
    }
    }

    View full-size slide

  86. Quite a bit to chew

    View full-size slide

  87. But we are not done yet!

    View full-size slide

  88. Scenario based testing
    Given - When - Then

    View full-size slide

  89. Test your Command
    Handler
    $
    t
    h
    i
    s
    -
    >
    s
    c
    e
    n
    a
    r
    i
    o
    -
    >
    g
    i
    v
    e
    n
    (
    [
    n
    e
    w C
    o
    m
    p
    a
    n
    y
    R
    e
    g
    i
    s
    t
    e
    r
    e
    d
    E
    v
    e
    n
    t
    (
    1
    2
    3
    )
    ]
    )
    -
    >
    w
    h
    e
    n
    (
    n
    e
    w E
    n
    a
    b
    l
    e
    A
    p
    p
    F
    o
    r
    C
    o
    m
    p
    a
    n
    y
    C
    o
    m
    m
    a
    n
    d
    (
    4
    2
    , 1
    2
    3
    )
    )
    -
    >
    t
    h
    e
    n
    (
    [
    n
    e
    w A
    p
    p
    E
    n
    a
    b
    l
    e
    d
    E
    v
    e
    n
    t
    (
    4
    2
    , 1
    2
    3
    )
    ]
    )
    ;

    View full-size slide

  90. Or your aggregate
    $
    t
    h
    i
    s
    -
    >
    s
    c
    e
    n
    a
    r
    i
    o
    -
    >
    g
    i
    v
    e
    n
    (
    [
    n
    e
    w C
    o
    m
    p
    a
    n
    y
    R
    e
    g
    i
    s
    t
    e
    r
    e
    d
    E
    v
    e
    n
    t
    (
    1
    2
    3
    )
    ]
    )
    -
    >
    w
    h
    e
    n
    (
    f
    u
    n
    c
    t
    i
    o
    n (
    $
    c
    o
    m
    p
    a
    n
    y
    ) {
    $
    c
    o
    m
    p
    a
    n
    y
    -
    >
    e
    n
    a
    b
    l
    e
    A
    p
    p
    (
    4
    2
    )
    ;
    }
    )
    -
    >
    t
    h
    e
    n
    (
    [
    n
    e
    w A
    p
    p
    E
    n
    a
    b
    l
    e
    d
    E
    v
    e
    n
    t
    (
    4
    2
    , 1
    2
    3
    )
    ]
    )
    ;

    View full-size slide

  91. Don't forget your read
    models
    $
    t
    h
    i
    s
    -
    >
    s
    c
    e
    n
    a
    r
    i
    o
    -
    >
    g
    i
    v
    e
    n
    (
    [
    ]
    )
    -
    >
    w
    h
    e
    n
    (
    n
    e
    w C
    o
    m
    p
    a
    n
    y
    R
    e
    g
    i
    s
    t
    e
    r
    e
    d
    E
    v
    e
    n
    t
    (
    1
    2
    3
    , '
    A
    c
    m
    e I
    n
    c
    '
    )
    )
    -
    >
    t
    h
    e
    n
    (
    [
    n
    e
    w C
    o
    m
    p
    a
    n
    y
    R
    e
    g
    i
    s
    t
    r
    a
    t
    i
    o
    n
    (
    1
    2
    3
    , '
    A
    c
    m
    e I
    n
    c
    '
    )
    ]
    )
    ;

    View full-size slide

  92. Time travel is possible!
    Use events you recorded to create a new report
    multiple years after the fact

    View full-size slide

  93. You made a mistake in a projection?
    So what? Correct your projector and recreate your read model
    from your event stream

    View full-size slide

  94. Questions?
    Feedback:
    https://joind.in/talk/3375d
    @willemjanz
    Freenode: #qandidate

    View full-size slide

  95. More information
    http://codebetter.com/gregyoung/2010/02/20/why-use-
    event-sourcing/
    http://codebetter.com/gregyoung/2010/02/13/cqrs-and-
    event-sourcing/
    http://martinfowler.com/eaaDev/EventSourcing.html
    http://martinfowler.com/bliki/CQRS.html
    http://www.axonframework.org/docs/2.3/domain-
    modeling.html
    http://labs.qandidate.com/

    View full-size slide