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

Event Sourcing, or Why ActiveRecord Must Die

Event Sourcing, or Why ActiveRecord Must Die

Much has been said about the dangers with ActiveRecord, but the advice is usually limited to avoiding callbacks or not building God models. We still use it because there hasn't been a viable alternative. It is not actually a trait unique to ActiveRecord that makes it dangerous, however--it's because it's an ORM, and all ORMs must die.

With Event Sourcing, we can build Ruby applications that are simple, scalable, extensible, and elegant without ActiveRecord or any other ORM anywhere in sight. We also get a free time machine as a bonus, and we'll find out that Event Sourcing is a lot older than we might think.

I gave this presentation at RubyConf AU 2016 in Gold Coast, QLD.

If you found this interesting, you can find my more recent (and way more in-depth) talk on Event Sourcing here: https://speakerdeck.com/vonconrad/an-in-depth-look-at-event-sourcing-with-cqrs

Sebastian von Conrad

February 11, 2016
Tweet

More Decks by Sebastian von Conrad

Other Decks in Programming

Transcript

  1. Event Sourcing
    (or why ActiveRecord must die)
    Sebastian von Conrad
    @vonconrad

    View full-size slide

  2. Source: swedenflag.facts.co

    View full-size slide

  3. Source: brandwatch.com

    View full-size slide

  4. Source: metro.co.uk

    View full-size slide

  5. Warm up audience?
    Nope.

    View full-size slide

  6. Make me feel
    comfortable.

    View full-size slide

  7. This is important
    to me.

    View full-size slide

  8. Any mistakes I make
    are recorded on video
    and in your memory.

    View full-size slide

  9. Because in the
    real world,
    mistakes are forever.

    View full-size slide

  10. It’s the way the
    world works.

    View full-size slide

  11. The things that
    happen to us are
    immutable.

    View full-size slide

  12. This talk is an
    append-only list of
    immutable sentences.

    View full-size slide

  13. And life is an
    append-only list of
    immutable events.

    View full-size slide

  14. And somehow we
    just learn to deal.

    View full-size slide

  15. Except that’s not how
    we build software.

    View full-size slide

  16. With software, we
    get to be revisionists.

    View full-size slide

  17. We get to play
    $DEITY.

    View full-size slide

  18. We can
    DELETE.

    View full-size slide

  19. We can change
    history by erasing
    information.

    View full-size slide

  20. We’re taught
    to do this.

    View full-size slide

  21. ActiveRecord::Base
    .delete
    .delete_all
    .destroy
    .destroy_all
    #delete
    #destroy
    #destroy!
    #mark_for_destruction

    View full-size slide

  22. class User
    has_many :widgets, dependent: :destroy
    end

    View full-size slide

  23. But really, we DELETE
    just because we can.

    View full-size slide

  24. Source: wikipedia.org

    View full-size slide

  25. Source: uchicago.edu

    View full-size slide

  26. We have the technical
    (r)evolution to thank.

    View full-size slide

  27. It’s not a feature,
    it’s a bug.

    View full-size slide

  28. Give me my
    stone tablet back,
    goddammit.

    View full-size slide

  29. Data is the most
    important thing
    we have.

    View full-size slide

  30. It’s the core of
    what we do.

    View full-size slide

  31. Data survives when
    technology doesn’t.

    View full-size slide

  32. Yet we DELETE it.

    View full-size slide

  33. Sometimes we get rid
    of it accidentally.

    View full-size slide

  34. Q: Biggest screwup?
    A: Usually data loss.

    View full-size slide

  35. Sometimes we get rid
    of it on purpose.

    View full-size slide

  36. But what if we need
    it after it’s gone?

    View full-size slide

  37. Often it has
    widespread and/or
    unanticipated
    consequences.

    View full-size slide

  38. Run @user.destroy
    and see what
    happens next.

    View full-size slide

  39. More importantly.

    View full-size slide

  40. Why would we get rid
    of something that has
    value?

    View full-size slide

  41. Sure, maybe not all
    data has value.

    View full-size slide

  42. But how do know
    know?

    View full-size slide

  43. How can you know
    for sure that the data
    is never going to be
    relevant?

    View full-size slide

  44. Why would we get rid
    of something that has
    potential value?

    View full-size slide

  45. I’m not alone.

    View full-size slide

  46. paranoia
    acts_as_paranoid
    acts_as_archive
    permanent_records
    destroyed_at
    immortal
    acts_as_soft_deletable
    rails3_acts_as_paranoid
    acts_as_archival
    soft_deletion
    paranoid2
    paranoid
    Source: ruby-toolbox.com/categories/Active_Record_Soft_Delete

    View full-size slide

  47. I didn’t write these
    soft-delete gems for
    ActiveRecord.

    View full-size slide

  48. DELETE sucks.
    Here, have a
    workaround.

    View full-size slide

  49. Workarounds
    can be okay.

    View full-size slide

  50. If only there wasn’t
    something even more
    sinister lurking below.

    View full-size slide

  51. (I think) we can agree
    that @user.destroy is
    bad.

    View full-size slide

  52. But so is
    @user.update.

    View full-size slide

  53. When we UPDATE,
    we overwrite what
    was there.

    View full-size slide

  54. Why should we suddenly
    not care about the
    previous value?

    View full-size slide

  55. The old email address
    still has value.

    View full-size slide

  56. We’re replacing it.

    View full-size slide

  57. We’re deleting it, to
    put something else in
    its stead.

    View full-size slide

  58. Every UPDATE
    is a DELETE.

    View full-size slide

  59. And it’s worse,
    because it’s less
    explicit.

    View full-size slide

  60. We don’t notice that
    we’re doing it.

    View full-size slide

  61. Sure, we can work
    around this too.

    View full-size slide

  62. Change logs, audit
    logs, event logs,
    triggers.

    View full-size slide

  63. We find further
    workarounds to keep
    track of changes.

    View full-size slide

  64. But these workarounds
    are starting to get
    difficult.

    View full-size slide

  65. Makes me feel
    uncomfortable.

    View full-size slide

  66. (And no amount of fluff at
    the beginning of a talk can
    fix that discomfort.)

    View full-size slide

  67. Why should I have to
    go out of my way
    not to lose what’s
    most important?

    View full-size slide

  68. The more I thought
    about it…

    View full-size slide

  69. DELETE and UPDATE
    are the enemies.

    View full-size slide

  70. Stop the ride.
    I want to get off.

    View full-size slide

  71. But if I don’t have
    DELETE and UPDATE,
    what do I have?

    View full-size slide

  72. What could I do if all
    I had was INSERT and
    SELECT?

    View full-size slide

  73. What if it was
    append-only?

    View full-size slide

  74. What if it was
    immutable?

    View full-size slide

  75. Can I build software
    like how the real
    world works?

    View full-size slide

  76. Can I record the things
    that happen, as they
    happen, and never
    change them?

    View full-size slide

  77. Event Sourcing.

    View full-size slide

  78. I felt something I
    hadn’t felt since 2006.

    View full-size slide

  79. This is a new way to
    build software and it will
    change our industry.

    View full-size slide

  80. Event Sourcing is
    pretty easy to explain.

    View full-size slide

  81. ActiveRecord stores
    the current state of an
    object in a database.

    View full-size slide

  82. When state changes, we
    change the database
    representation.

    View full-size slide

  83. John just got married.
    He wants to take his
    partner’s last name.

    View full-size slide

  84. ActiveRecord
    #last_name: “Reed” ...>
    + --- + ---------- + --------- + --- +
    | id | first_name | last_name | ... |
    | --- | ---------- | --------- | --- |
    | 216 | John | Reed | ... |
    | ... | ... | ... | ... |
    + --- + ---------- + --------- + --- +

    View full-size slide

  85. ActiveRecord
    @user.update(last_name: “Hill”)

    View full-size slide

  86. ActiveRecord
    #last_name: “Hill”, ...>
    + --- + ---------- + --------- + --- +
    | id | first_name | last_name | ... |
    | --- | ---------- | --------- | --- |
    | 216 | John | Hill | ... |
    | ... | ... | ... | ... |
    + --- + ---------- + --------- + --- +

    View full-size slide

  87. Event Sourcing
    doesn’t do that.

    View full-size slide

  88. Event Sourcing stores
    the events that have
    happened to the object.

    View full-size slide

  89. Then sources the
    current state by
    replaying events.

    View full-size slide

  90. Event Sourcing
    #last_name: “Reed”, ...>
    {
    id: 216,
    type: “user_signed_up”,
    body:
    { first_name: “John”, last_name: “Reed” }
    }

    View full-size slide

  91. Event Sourcing
    @user.change_name(last_name: “Hill”)
    {
    id: 216,
    type: “user_changed_name”,
    body:
    { last_name: “Hill” }
    }

    View full-size slide

  92. Event Sourcing
    #last_name: “Hill”, ...>
    {
    type: “user_sign_up”,
    body: { first_name: “John”, last_name: “Reed” }
    },
    {
    type: “user_changed_name”,
    body: { last_name: “Hill” }
    }

    View full-size slide

  93. The data becomes an
    append-only list of
    immutable events.

    View full-size slide

  94. If a mistake is made,
    we correct it with
    another event.

    View full-size slide

  95. Just like in real life.

    View full-size slide

  96. But I was wrong.

    View full-size slide

  97. It’s not this fancy new
    paradigm that will
    change the world.

    View full-size slide

  98. Because it’s actually
    not new at all.

    View full-size slide

  99. See, the thing is…
    ActiveRecord has no
    respect for history.

    View full-size slide

  100. No respect for history
    of data, certainly.

    View full-size slide

  101. But also no respect
    for methodologies that
    existed before it came
    and screwed it all up.

    View full-size slide

  102. To understand how
    to respect history,
    we must look towards
    history itself.

    View full-size slide

  103. At the very core of
    every business…

    View full-size slide

  104. There is one system
    that stands above
    all others.

    View full-size slide

  105. Here’s the thing: your
    accounting system is
    Event Sourced.

    View full-size slide

  106. A bank account’s
    current state is its
    balance.

    View full-size slide

  107. + ---------------- + -------- + ------- +
    | | Debit | Credit |
    | ---------------- | ------- | -------- |
    | ... | | |
    | ---------------- | --------| -------- |
    | Total balance | | $405.00 |
    + ---------------- + ------- + -------- +

    View full-size slide

  108. But the balance is
    ephemeral.

    View full-size slide

  109. The balance is sourced
    from adding up all
    credits and debits.

    View full-size slide

  110. + ---------------- + -------- + ------- +
    | | Debit | Credit |
    | ---------------- | ------- | -------- |
    | Training stipend | | $1000.00 |
    | RubyConf ticket | $595.00 | |
    | ---------------- | --------| -------- |
    | Total balance | | $405.00 |
    + ---------------- + ------- + -------- +

    View full-size slide

  111. The transactions are
    what matters.

    View full-size slide

  112. A bank account is an
    append-only list of
    immutable transactions.

    View full-size slide

  113. You can’t DELETE or
    UPDATE a bank
    account transaction.

    View full-size slide

  114. Imagine the chaos.

    View full-size slide

  115. How would you feel if
    your bank started
    messing with your
    account transactions?

    View full-size slide

  116. How would you feel if
    you couldn’t calculate
    your account balance?

    View full-size slide

  117. So it’s event sourced.

    View full-size slide

  118. This is what we’ve
    been doing for
    500+ years.

    View full-size slide

  119. It’s robust.

    View full-size slide

  120. It’s scalable.

    View full-size slide

  121. It’s auditable.

    View full-size slide

  122. It’s trustworthy.

    View full-size slide

  123. It’s proven.

    View full-size slide

  124. And if this is how we
    deal with our most
    important data…

    View full-size slide

  125. …why can’t we give
    the same service to
    our other data?

    View full-size slide

  126. Our users’ data.

    View full-size slide

  127. Why are we so caught
    up with the idea of
    mapping object state to
    database tables?

    View full-size slide

  128. We need state, yes.

    View full-size slide

  129. But we don’t need to
    persist the current
    state model.

    View full-size slide

  130. This is what
    ActiveRecord
    gets wrong.

    View full-size slide

  131. (This goes for all
    other ORMs too.)

    View full-size slide

  132. It’s encouraging us to
    do the wrong thing
    with our data.

    View full-size slide

  133. It’s teaching us to
    DELETE and UPDATE.

    View full-size slide

  134. And it is why
    ActiveRecord
    must die.

    View full-size slide

  135. Because we can have
    nice things without it.

    View full-size slide

  136. We can have the same
    objects in code while
    persisting them
    differently.

    View full-size slide

  137. We can record
    everything that
    happens.

    View full-size slide

  138. So that we never
    purposely or accidentally
    delete anything.

    View full-size slide

  139. And it’s been hard.

    View full-size slide

  140. We’ve solved
    problems, yes.

    View full-size slide

  141. And we’ve replaced
    them with new
    problems!

    View full-size slide

  142. #nosilverbullets

    View full-size slide

  143. But if you care
    about historical data
    (and you should).

    View full-size slide

  144. Consider
    Event Sourcing.

    View full-size slide

  145. Think about what your app
    would look like without
    DELETE and UPDATE.

    View full-size slide

  146. How can you build
    your app with only
    INSERT and SELECT?

    View full-size slide

  147. There’s a whole world
    of Event Sourcing out
    there.

    View full-size slide

  148. Have a look at it.

    View full-size slide

  149. Come talk to me
    (and others).

    View full-size slide

  150. Thank you.
    Sebastian von Conrad
    @vonconrad

    View full-size slide