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

C00089fa70bfc238069005c7b4fbd15f?s=128

Sebastian von Conrad

February 11, 2016
Tweet

Transcript

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

    @vonconrad
  2. Fluff.

  3. Source: swedenflag.facts.co

  4. Source: brandwatch.com

  5. Source: metro.co.uk

  6. Warm up audience? Nope.

  7. Make me feel comfortable.

  8. This is important to me.

  9. Any mistakes I make are recorded on video and in

    your memory.
  10. Because in the real world, mistakes are forever.

  11. It’s the way the world works.

  12. The things that happen to us are immutable.

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

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

  15. And somehow we just learn to deal.

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

  17. With software, we get to be revisionists.

  18. We get to play $DEITY.

  19. We can DELETE.

  20. We can change history by erasing information.

  21. We’re taught to do this.

  22. CRUD

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

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

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

  26. Source: wikipedia.org

  27. Source: uchicago.edu

  28. None
  29. We have the technical (r)evolution to thank.

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

  31. Give me my stone tablet back, goddammit.

  32. Data is the most important thing we have.

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

  34. Data survives when technology doesn’t.

  35. Yet we DELETE it.

  36. Sometimes we get rid of it accidentally.

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

  38. Sometimes we get rid of it on purpose.

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

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

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

  42. More importantly.

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

  44. Sure, maybe not all data has value.

  45. But how do know know?

  46. How can you know for sure that the data is

    never going to be relevant?
  47. Why would we get rid of something that has potential

    value?
  48. I’m not alone.

  49. 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
  50. I didn’t write these soft-delete gems for ActiveRecord.

  51. DELETE sucks. Here, have a workaround.

  52. Workarounds can be okay.

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

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

  55. But so is @user.update.

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

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

  58. The old email address still has value.

  59. We’re replacing it.

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

  61. Every UPDATE is a DELETE.

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

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

  64. Sure, we can work around this too.

  65. Change logs, audit logs, event logs, triggers.

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

  67. But these workarounds are starting to get difficult.

  68. Makes me feel uncomfortable.

  69. (And no amount of fluff at the beginning of a

    talk can fix that discomfort.)
  70. Why should I have to go out of my way

    not to lose what’s most important?
  71. The more I thought about it…

  72. DELETE and UPDATE are the enemies.

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

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

    I have?
  75. What could I do if all I had was INSERT

    and SELECT?
  76. What if it was append-only?

  77. What if it was immutable?

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

  79. Can I record the things that happen, as they happen,

    and never change them?
  80. Event Sourcing.

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

  82. This is a new way to build software and it

    will change our industry.
  83. Event Sourcing is pretty easy to explain.

  84. ActiveRecord stores the current state of an object in a

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

  86. John just got married. He wants to take his partner’s

    last name.
  87. ActiveRecord #<User id: 216, first_name: “John”, last_name: “Reed” ...> +

    --- + ---------- + --------- + --- + | id | first_name | last_name | ... | | --- | ---------- | --------- | --- | | 216 | John | Reed | ... | | ... | ... | ... | ... | + --- + ---------- + --------- + --- +
  88. ActiveRecord @user.update(last_name: “Hill”)

  89. ActiveRecord #<User id: 216, first_name: “John”, last_name: “Hill”, ...> +

    --- + ---------- + --------- + --- + | id | first_name | last_name | ... | | --- | ---------- | --------- | --- | | 216 | John | Hill | ... | | ... | ... | ... | ... | + --- + ---------- + --------- + --- +
  90. Event Sourcing doesn’t do that.

  91. Event Sourcing stores the events that have happened to the

    object.
  92. Then sources the current state by replaying events.

  93. Event Sourcing #<User id: 216, first_name: “John”, last_name: “Reed”, ...>

    { id: 216, type: “user_signed_up”, body: { first_name: “John”, last_name: “Reed” } }
  94. Event Sourcing @user.change_name(last_name: “Hill”) { id: 216, type: “user_changed_name”, body:

    { last_name: “Hill” } }
  95. Event Sourcing #<User id: 216, first_name: “John”, last_name: “Hill”, ...>

    { type: “user_sign_up”, body: { first_name: “John”, last_name: “Reed” } }, { type: “user_changed_name”, body: { last_name: “Hill” } }
  96. The data becomes an append-only list of immutable events.

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

    event.
  98. Just like in real life.

  99. But I was wrong.

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

    world.
  101. Because it’s actually not new at all.

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

  103. No respect for history of data, certainly.

  104. But also no respect for methodologies that existed before it

    came and screwed it all up.
  105. To understand how to respect history, we must look towards

    history itself.
  106. At the very core of every business…

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

  108. None
  109. Here’s the thing: your accounting system is Event Sourced.

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

  111. + ---------------- + -------- + ------- + | | Debit

    | Credit | | ---------------- | ------- | -------- | | ... | | | | ---------------- | --------| -------- | | Total balance | | $405.00 | + ---------------- + ------- + -------- +
  112. But the balance is ephemeral.

  113. The balance is sourced from adding up all credits and

    debits.
  114. + ---------------- + -------- + ------- + | | Debit

    | Credit | | ---------------- | ------- | -------- | | Training stipend | | $1000.00 | | RubyConf ticket | $595.00 | | | ---------------- | --------| -------- | | Total balance | | $405.00 | + ---------------- + ------- + -------- +
  115. The transactions are what matters.

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

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

  118. Imagine the chaos.

  119. How would you feel if your bank started messing with

    your account transactions?
  120. How would you feel if you couldn’t calculate your account

    balance?
  121. So it’s event sourced.

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

  123. It’s robust.

  124. It’s scalable.

  125. It’s auditable.

  126. It’s trustworthy.

  127. It’s proven.

  128. And if this is how we deal with our most

    important data…
  129. …why can’t we give the same service to our other

    data?
  130. Our users’ data.

  131. Why are we so caught up with the idea of

    mapping object state to database tables?
  132. We need state, yes.

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

  134. This is what ActiveRecord gets wrong.

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

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

    data.
  137. It’s teaching us to DELETE and UPDATE.

  138. And it is why ActiveRecord must die.

  139. Because we can have nice things without it.

  140. We can have the same objects in code while persisting

    them differently.
  141. We can record everything that happens.

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

  143. None
  144. And it’s been hard.

  145. Mindshift.

  146. We’ve solved problems, yes.

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

  148. #nosilverbullets

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

  150. Consider Event Sourcing.

  151. Think about what your app would look like without DELETE

    and UPDATE.
  152. How can you build your app with only INSERT and

    SELECT?
  153. There’s a whole world of Event Sourcing out there.

  154. Have a look at it.

  155. Come talk to me (and others).

  156. Thank you. Sebastian von Conrad @vonconrad