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

Employing CQRS and Event Sourcing to Build an MVP (Symfony Live San Francisco 2017)

Employing CQRS and Event Sourcing to Build an MVP (Symfony Live San Francisco 2017)

Learning about Command Query Responsibility Segregation (CQRS) and Event Sourcing can be both exciting and confusing. It sounds great, but how does it work in the real world? Won't it be a lot of work before you even get started? Will it be worth the investment and when will that investment start paying off? Are these technologies appropriate for building a minimum viable product (MVP)? Find out how these questions were answered for one team as they set out to build their MVP.


Beau Simensen

October 19, 2017


  1. Employing CQRS and Event Sourcing to Build an MVP Beau

    Simensen • @beausimensen • beau.io joind.in/talk/3d016
  2. What is CQRS?

  3. Command / Query Responsibility Segregation

  4. None
  5. None
  6. What is Event Sourcing?

  7. None
  8. None
  9. None
  10. None
  11. None
  12. Why do ES + CQRS?

  13. None
  14. What is an MVP?

  15. None
  16. Fintech! Accounting + Big Data

  17. None
  18. None
  19. MVP Criteria

  20. Address Book

  21. Deals

  22. Solid No rewrites every two years

  23. Solid Jump on features quickly

  24. Multi-Tenant

  25. Single Page Application (SPA)

  26. None
  27. React + Redux Flux

  28. Material Design Material-UI

  29. Internal Framework API + CLI + Container

  30. Internal Infrastructure Event Sourcing + CQRS

  31. None
  32. Me

  33. The Cowboy

  34. The Junior

  35. (that's it)

  36. Testing

  37. Modern PHP

  38. We built our ES+CQRS Infrastructure as a team

  39. None
  40. Choose Boring Technology Dan McKinley http://mcfunley.com/choose-boring-technology

  41. "Boring" should not be conflated with "bad." — Dan McKinley

  42. ... three innovation tokens

  43. React 1 Token

  44. React for our team? 2 - 3 Tokens

  45. Redux 1 Token

  46. Redux for our team? 2 - 3 Tokens

  47. Material UI 1 Token

  48. Material UI for our team? 2 - 3 Tokens

  49. Event Sourcing 1 Token

  50. Event Sourcing for our team? 2 - 3 Tokens

  51. CQRS 1 Token

  52. CQRS for our team? 2 - 3 Tokens

  53. PSR-7 1 Token

  54. PSR-7 for our team? Boring!

  55. PHP Boring!

  56. MySQL Boring!

  57. Envoyer + Forge Boring!

  58. Best case? 5 Tokens

  59. Worst cases? 10-15 Tokens

  60. It took our team SIX MONTHS to reach MVP

  61. Similar functionality could have been built in ONE MONTH using

    a "boring" framework & HTML templates
  62. We had a solid foundation

  63. It felt like a desktop application

  64. Six months from MVP we threw in the towel

  65. None
  66. Was it the fault of the stack? — me, every

    day for the next few months
  67. Surprise! We're just going to build a CRM. — two

    weeks after MVP was ready
  68. PIVOT

  69. Sales and marketing could not sell the product

  70. Saturated and Competitive Market

  71. Knowing that sooner would have saved us a ton of

  72. Catch-22

  73. If the plan was to just build a CRM I

    wouldn't have gotten involved.
  74. None
  75. Reflection Properties Serializer Optimized for DX

  76. Reflection Properties Serializer Started to hurt after 3 months in

  77. Search Read Model Awesome!

  78. History Read Models Neat, but limited...

  79. History Read Models Required augmenting events with more info

  80. Timeline Full power of Event Sourcing + CQRS

  81. Designed for async; never implemented No need to worry about

    eventual consistency
  82. Events change Especially if your domain isn't stable

  83. Version

  84. Upcast

  85. Lazy Upcast

  86. In Place Migration

  87. Copy Migration

  88. In Place / Copy Migration

  89. Required downtime for safety

  90. Rebuilt all read models from scratch

  91. 30 seconds For the first month

  92. 10 minutes By middle of second month

  93. Replaying events broke on some changes

  94. Rebuilding Read Models (not just when migrating the event stream...)

  95. Nuclear Option Rebuild ALL Read Models

  96. Rebuilding Individual Read Models Helped a lot with downtime, smaller

    sets of events
  97. Mostly optimized for Read Since write load was generally low...

  98. False sense of security Rebuilding Read Models became expensive

  99. Rebuilding Read Models while app was active Dangerous!

  100. Rebuilding Read Models while app was active Deemed acceptable risk

    while load was low
  101. Rebuilding Read Models while app was active Weird side effects

    as rebuild started to take longer
  102. Solution? Queue events so that new events would not be

  103. Solution? Replay old events into to new read model repository

  104. Solution? Swap new repository for old repository

  105. Solution? Start reading events from queue again and start projecting

  106. Solution! Follow Store

  107. ChatOps

  108. Migrations

  109. Rebuilding Read Models!

  110. Is Read Model up to date?

  111. Private State

  112. Too strict CQRS led to extra Read Models we probably

    didn't need...
  113. Private State = Private Read Models

  114. Eventually moved toward private state for Model

  115. Eventually moved toward private state for Read Model

  116. Eventually moved toward private state for Services

  117. None
  118. Biggest Takeaway? Slower Development.

  119. Command -> Command Bus -> Command Handler -> Model ->

    Events -> Event Store -> Event Bus -> Projector -> Read Model!
  120. Adding one new field...

  121. Search huge win

  122. Timeline huge win

  123. Retroactive Features

  124. Natural Evolution

  125. Event Sourcing makes sense if the Model is known and

    stable How often is that the case for an MVP?
  126. CQRS makes sense if Read Model is not known /

    flexible Good fit for an MVP!
  127. CQRS makes sense if Read Model is not known /

    flexible At a cost...
  128. Can you use an off-the-shelf framework?

  129. Event Store

  130. Test Harness

  131. Good Fit!

  132. Rolling an ES+CQRS framework ourself was expensive but was a

    great investment for the team.
  133. Not sure I'd make the same decision today...

  134. It DID work though! (But development pace was considerably slower...)

  135. Support From Management

  136. Had that support initially

  137. Unrealistic expectations

  138. Eventually just a feature race

  139. Eventually just wanted CRUD

  140. Pivot changed everything

  141. We couldn't sell the MVP This made ES+CQRS infinitely more

  142. None
  143. Thanks! @sensiolabs • @thatpodcast Beau Simensen • @beausimensen • beau.io

  144. • Stop overthinking…Just stop!