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

Let's write some history - DPC 2015

Let's write some history - DPC 2015

45 minute talk on Event Sourcing. Given on Dutch PHP Conference 2015

Willem-Jan Zijderveld

June 26, 2015
Tweet

More Decks by Willem-Jan Zijderveld

Other Decks in Programming

Transcript

  1. 1/92
    Event Sourcing
    Let's write some history
    https://joind.in/14226

    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 and 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 most
    recent state
    gets stored

    View full-size slide

  8. What was the previous
    state?

    View full-size slide

  9. Why did the state
    change?

    View full-size slide

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

    View full-size slide

  11. A company has one or
    more connected accounts

    View full-size slide

  12. A company has one or
    more enabled applications

    View full-size slide

  13. An account has access to
    one or more applications

    View full-size slide

  14. Complicated solutions to store and
    retrieve the data

    View full-size slide

  15. But we manage
    Until...

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  19. Revoking access to an application for
    an account

    View full-size slide

  20. You could lose when the access was
    revoked

    View full-size slide

  21. You could lose why it got revoked

    View full-size slide

  22. You could lose for which application
    it was revoked

    View full-size slide

  23. You wouldn't know anything anymore

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  26. 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
    Past revocations are gone

    View full-size slide

  27. How does Event Sourcing
    help me with that?

    View full-size slide

  28. Store your data in
    a different way

    View full-size slide

  29. Record what has changed
    The resulting state becomes a natural effect

    View full-size slide

  30. A serie of facts
    CompanyRegistered
    AppEnabled
    AccountConnected
    AccessGrantedToApp

    View full-size slide

  31. Been there, done that

    View full-size slide

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

    View full-size slide

  33. Your version control is
    event sourced

    View full-size slide

  34. Sure thing, but how?
    There isn't one true answer

    View full-size slide

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

    View full-size slide

  36. Domain Driven Design
    The business should be reflected in your code

    View full-size slide

  37. Entity
    An model with an identity

    View full-size slide

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

    View full-size slide

  39. I want to update my
    model
    How do I do that?

    View full-size slide

  40. Record the change

    View full-size slide

  41. 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

  42. But we want to record an
    event

    View full-size slide

  43. <
    ?
    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

  44. 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
    )
    ;
    }
    Just one possible implementation

    View full-size slide

  45. /
    / 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

  46. Save your events in an
    eventstore

    View full-size slide

  47. Reloading your model

    View full-size slide

  48. <
    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

  49. <
    ?
    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

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

    View full-size slide

  51. DomainMessage
    Identifier
    Sequencenumber
    Payload
    Timestamp
    Metadata

    View full-size slide

  52. Identifier + sequence
    number

    View full-size slide

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

    View full-size slide

  54. 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

  55. Timestamp
    It tells you when it happened

    View full-size slide

  56. Metadata
    Descriptive, not structural

    View full-size slide

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

    View full-size slide

  58. 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

  59. 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
    ] = $
    e
    v
    e
    n
    t
    -
    >
    g
    e
    t
    A
    c
    c
    o
    u
    n
    t
    I
    d
    (
    )
    ;
    }

    View full-size slide

  60. 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

  61. 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
    ] =
    $
    e
    v
    e
    n
    t
    -
    >
    g
    e
    t
    A
    c
    c
    o
    u
    n
    t
    I
    d
    (
    )
    ;
    }

    View full-size slide

  62. We can retrieve all
    AccessGranted events for
    December

    View full-size slide

  63. Won't this be slow?

    View full-size slide

  64. CQRS
    Command Query Responsibility Segregation

    View full-size slide

  65. Separate your writes and
    your reads

    View full-size slide

  66. Read Models
    Create them from events using projections
    Specific read models for specific views in your application

    View full-size slide

  67. 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

  68. 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

  69. Use the right tool for the
    right job

    View full-size slide

  70. Possibilities are endless

    View full-size slide

  71. 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

  72. So.. how does this flow
    work in an application?
    We'll use Commands

    View full-size slide

  73. The write part of CQRS

    View full-size slide

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

    View full-size slide

  75. From Controller
    to CommandHandler
    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

  76. 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

  77. 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

  78. From Aggregate
    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

  79. 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

  80. Controller -> CommandBus -> CommandHandler ->
    AggregateRoot -> Event -> EventStore -> EventBus -> Projectors
    -> Read Model

    View full-size slide

  81. Quite a bit to chew
    Try not to reinvent everything yourself

    View full-size slide

  82. Testing
    Scenario based testing
    Given - When - Then

    View full-size slide

  83. 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

  84. 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

  85. 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

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

    View full-size slide

  87. 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

  88. Questions?
    joind.in/14226
    @willemjanz
    Freenode: #qandidate

    View full-size slide

  89. 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