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

Rethinking "State Management"

Rethinking "State Management"

Persisting the State is an integral part of any application, and it profoundly influences how we architect the application. But do we need to store the state in the first place? Is there any alternative?

Join me to experience the difference perspective of State Management.

Tamizhvendan S

July 10, 2016
Tweet

More Decks by Tamizhvendan S

Other Decks in Programming

Transcript

  1. { "tables" : [{"id" : 1, "status" : "available"}] }

    { "tables" : [{"id" : 1, "status" : "waiting_for_order"}] } { "tables" : [{"id" : 1, "status" : "in_service"}] }
  2. t0

  3. t0

  4. Serve Drink Closed Tab Placed Order Opened Tab Order InProgress

    Open Tab Place Order Serve Drink Prepare Food
  5. Serve Drink Prepare Food Closed Tab Placed Order Opened Tab

    Order InProgress Open Tab Place Order Serve Drink Prepare Food
  6. Serve Drink Prepare Food Serve Food Closed Tab Placed Order

    Opened Tab Order InProgress Open Tab Place Order Serve Drink Prepare Food
  7. Serve Drink Prepare Food Serve Food Closed Tab Placed Order

    Opened Tab Order InProgress Open Tab Place Order Serve Drink Prepare Food
  8. Serve Drink Prepare Food Serve Food Closed Tab Placed Order

    Opened Tab Order InProgress Open Tab Place Order Serve Drink Prepare Food
  9. Serve Drink Prepare Food Serve Food Closed Tab Placed Order

    Opened Tab Order InProgress Served Order Open Tab Place Order Serve Drink Prepare Food
  10. Serve Drink Prepare Food Serve Food Closed Tab Placed Order

    Opened Tab Order InProgress Served Order Open Tab Place Order Serve Drink Prepare Food
  11. Serve Drink Prepare Food Serve Food Closed Tab Placed Order

    Opened Tab Order InProgress Served Order Open Tab Place Order Serve Drink Prepare Food Close Tab
  12. Serve Drink Prepare Food Serve Food Closed Tab Placed Order

    Opened Tab Order InProgress Served Order Open Tab Place Order Serve Drink Prepare Food Close Tab
  13. State X State Y Command // State -> Command ->

    State let evolve state command = let newState = // ... newState
  14. State X State Y Command // State -> Command ->

    State let evolve state command = let newState = // ... newState
  15. State X State Y Command // State -> Command ->

    State let evolve state command = let newState = // ... newState let state = ??
  16. Closed Tab Opened Tab Open Tab initial state Tab Opened

    event // State -> Command -> Event list let execute state command = let events = // ... events
  17. Closed Tab Placed Order Opened Tab Order InProgress Served Order

    Tab Opened Order Placed Drink Served Food Prepared
  18. Closed Tab Placed Order Opened Tab Order InProgress Served Order

    Tab Opened Order Placed Drink Served Food Prepared Drink Served Food Prepared Food Served
  19. Closed Tab Placed Order Opened Tab Order InProgress Served Order

    Tab Opened Order Placed Drink Served Food Prepared Drink Served Food Prepared Food Served Order Served
  20. Closed Tab Placed Order Opened Tab Order InProgress Served Order

    Tab Opened Order Placed Drink Served Food Prepared Drink Served Food Prepared Food Served Tab Closed Order Served
  21. Events Are Facts It’s like a Bank Statement! Closed Tab

    Opened Tab Tab Opened event current state new state
  22. // State -> Event -> State let apply state event

    = let newState = // ... newState Events Are Facts It’s like a Bank Statement! Closed Tab Opened Tab Tab Opened event current state new state
  23. Closed Tab Placed Order Opened Tab Order InProgress Served Order

    Tab Opened Order Placed Drink Served Food Prepared Drink Served Food Prepared Food Served Tab Closed Order Served
  24. Closed Tab Placed Order Opened Tab Order InProgress Served Order

    Tab Opened Order Placed Drink Served Food Prepared Drink Served Food Prepared Food Served Tab Closed Order Served
  25. Tab Opened Closed Tab Placed Order Opened Tab Order InProgress

    Served Order Tab Opened Order Placed Drink Served Food Prepared Drink Served Food Prepared Food Served Tab Closed Order Served
  26. Tab Opened Order Placed Closed Tab Placed Order Opened Tab

    Order InProgress Served Order Tab Opened Order Placed Drink Served Food Prepared Drink Served Food Prepared Food Served Tab Closed Order Served
  27. Tab Opened Order Placed Drink Served Closed Tab Placed Order

    Opened Tab Order InProgress Served Order Tab Opened Order Placed Drink Served Food Prepared Drink Served Food Prepared Food Served Tab Closed Order Served
  28. Tab Opened Order Placed Drink Served Food Prepared Closed Tab

    Placed Order Opened Tab Order InProgress Served Order Tab Opened Order Placed Drink Served Food Prepared Drink Served Food Prepared Food Served Tab Closed Order Served
  29. Tab Opened Order Placed Drink Served Food Prepared Food Served

    Closed Tab Placed Order Opened Tab Order InProgress Served Order Tab Opened Order Placed Drink Served Food Prepared Drink Served Food Prepared Food Served Tab Closed Order Served
  30. Tab Opened Order Placed Drink Served Food Prepared Food Served

    Order Served Closed Tab Placed Order Opened Tab Order InProgress Served Order Tab Opened Order Placed Drink Served Food Prepared Drink Served Food Prepared Food Served Tab Closed Order Served
  31. Tab Opened Order Placed Drink Served Food Prepared Food Served

    Order Served Tab Closed Closed Tab Placed Order Opened Tab Order InProgress Served Order Tab Opened Order Placed Drink Served Food Prepared Drink Served Food Prepared Food Served Tab Closed Order Served
  32. Tab Opened Order Placed Drink Served Food Prepared Food Served

    Order Served Tab Closed It’s append only! Closed Tab Placed Order Opened Tab Order InProgress Served Order Tab Opened Order Placed Drink Served Food Prepared Drink Served Food Prepared Food Served Tab Closed Order Served
  33. past events Closed Tab initial state // State -> Event

    -> State let apply state event = let newState = // ... newState Tab Opened Order Placed Drink Served Food Prepared Food Served Order Served Tab Closed
  34. Closed Tab Tab Opened Opened Tab past events Closed Tab

    initial state // State -> Event -> State let apply state event = let newState = // ... newState Tab Opened Order Placed Drink Served Food Prepared Food Served Order Served Tab Closed
  35. Closed Tab Tab Opened Opened Tab past events Closed Tab

    initial state Opened Tab Order Placed Placed Order // State -> Event -> State let apply state event = let newState = // ... newState Tab Opened Order Placed Drink Served Food Prepared Food Served Order Served Tab Closed
  36. Closed Tab Tab Opened Opened Tab past events Closed Tab

    initial state Opened Tab Order Placed Placed Order Placed Order Drink Served Order InProgress // State -> Event -> State let apply state event = let newState = // ... newState Tab Opened Order Placed Drink Served Food Prepared Food Served Order Served Tab Closed
  37. Closed Tab Tab Opened Opened Tab past events Closed Tab

    initial state Opened Tab Order Placed Placed Order Placed Order Drink Served Order InProgress Food Prepared Order InProgress Order InProgress // State -> Event -> State let apply state event = let newState = // ... newState Tab Opened Order Placed Drink Served Food Prepared Food Served Order Served Tab Closed
  38. Closed Tab Tab Opened Opened Tab past events Closed Tab

    initial state Opened Tab Order Placed Placed Order Placed Order Drink Served Order InProgress Food Prepared Order InProgress Order InProgress Food Served Order InProgress Order InProgress // State -> Event -> State let apply state event = let newState = // ... newState Tab Opened Order Placed Drink Served Food Prepared Food Served Order Served Tab Closed
  39. Closed Tab Tab Opened Opened Tab past events Closed Tab

    initial state Opened Tab Order Placed Placed Order Placed Order Drink Served Order InProgress Food Prepared Order InProgress Order InProgress Food Served Order InProgress Order InProgress Order Served Served Order Order InProgress // State -> Event -> State let apply state event = let newState = // ... newState Tab Opened Order Placed Drink Served Food Prepared Food Served Order Served Tab Closed
  40. Closed Tab Tab Opened Opened Tab past events Closed Tab

    initial state Opened Tab Order Placed Placed Order Placed Order Drink Served Order InProgress Food Prepared Order InProgress Order InProgress Food Served Order InProgress Order InProgress Order Served Served Order Order InProgress Tab Closed Closed Tab Served Order // State -> Event -> State let apply state event = let newState = // ... newState Tab Opened Order Placed Drink Served Food Prepared Food Served Order Served Tab Closed
  41. Closed Tab Tab Opened Opened Tab past events Closed Tab

    initial state Opened Tab Order Placed Placed Order Placed Order Drink Served Order InProgress Food Prepared Order InProgress Order InProgress Food Served Order InProgress Order InProgress Order Served Served Order Order InProgress Tab Closed Closed Tab Served Order // State -> Event list -> State let computeState initialState pastEvents = List.fold apply initialState pastEvents // State -> Event -> State let apply state event = let newState = // ... newState Tab Opened Order Placed Drink Served Food Prepared Food Served Order Served Tab Closed
  42. Closed Tab Tab Opened Opened Tab past events Closed Tab

    initial state Opened Tab Order Placed Placed Order Placed Order Drink Served Order InProgress Food Prepared Order InProgress Order InProgress Food Served Order InProgress Order InProgress Order Served Served Order Order InProgress Tab Closed Closed Tab Served Order // State -> Event list -> State let computeState initialState pastEvents = List.fold apply initialState pastEvents // State -> Event -> State let apply state event = let newState = // ... newState Performance ?? Tab Opened Order Placed Drink Served Food Prepared Food Served Order Served Tab Closed
  43. // State -> Command -> State let evolve state command

    = let newState = // ... newState // State -> Command -> Event list let execute state command = let events = // ... events // State -> Event list -> State let computeState initialState pastEvents = List.fold apply initialState pastEvents // State -> Event -> State let apply state event = let newState = // ... newState
  44. // State -> Command -> State let evolve state command

    = let newState = // ... newState // State -> Command -> Event list let execute state command = let events = // ... events // State -> Event list -> State let computeState initialState pastEvents = List.fold apply initialState pastEvents // State -> Event -> State let apply state event = let newState = // ... newState // Event list -> Command -> Event list let evolve pastEvents command = let state = computeState TabClosed pastEvents execute state command
  45. // State -> Command -> State let evolve state command

    = let newState = // ... newState // Event list -> Command -> Event list let evolve pastEvents command = let state = computeState TabClosed pastEvents execute state command
  46. // State -> Command -> State let evolve state command

    = let newState = // ... newState // Event list -> Command -> Event list let evolve pastEvents command = let state = computeState TabClosed pastEvents execute state command We started with this
  47. // State -> Command -> State let evolve state command

    = let newState = // ... newState // Event list -> Command -> Event list let evolve pastEvents command = let state = computeState TabClosed pastEvents execute state command We started with this and evolved to this!
  48. // State -> Command -> State let evolve state command

    = let newState = // ... newState // Event list -> Command -> Event list let evolve pastEvents command = let state = computeState TabClosed pastEvents execute state command Current state is a left-fold of past events Event Sourcing - Greg Young We started with this and evolved to this!
  49. // State -> Command -> State let evolve state command

    = let newState = // ... newState // Event list -> Command -> Event list let evolve pastEvents command = let state = computeState TabClosed pastEvents execute state command currentState = foldl(pastEvents, initialState) Current state is a left-fold of past events Event Sourcing - Greg Young We started with this and evolved to this!
  50. // Event list -> Command -> Event list let evolve

    = // ... // Command -> int let getTableId command = // ... // int -> Event list let getPastEvents tableId = // ... Handling Commands
  51. // Event list -> Command -> Event list let evolve

    = // ... // Command -> int let getTableId command = // ... // int -> Event list let getPastEvents tableId = // ... // Command -> Event list let handleCommand command = let pastEvents = getTableId command |> getPastEvents evolve pastEvents command Handling Commands
  52. // Command -> Event list let handleCommand command = let

    pastEvents = getTableId command |> getPastEvents evolve pastEvents command // HttpRequest -> HttpResponse let commandHandler httpRequest = let command = // get Command from HTTP request let newEvents = handleCommand command saveEvents newEvents // return OK response Handling Commands
  53. { "tables" : [{"id" : 1, "status" : "available"}] }

    { "tables" : [{"id" : 1, "status" : "waiting_for_order"}] } { "tables" : [{"id" : 1, "status" : "in_service"}] } Data Model
  54. { "tables" : [{"id" : 1, "status" : "available"}] }

    { "tables" : [{"id" : 1, "status" : "waiting_for_order"}] } { "tables" : [{"id" : 1, "status" : "in_service"}] } Data Model Mutate during Commands
  55. { "tables" : [{"id" : 1, "status" : "available"}] }

    { "tables" : [{"id" : 1, "status" : "waiting_for_order"}] } { "tables" : [{"id" : 1, "status" : "in_service"}] } Data Model Mutate during Commands Fetch during Queries
  56. Event Projection Closed Tab Opened Tab Open Tab Tab Opened

    Publish Message Queue Tab Opened Kafka, RabbitMQ, etc.,
  57. Event Projection Closed Tab Opened Tab Open Tab Tab Opened

    Publish Listen Message Queue Tab Opened Kafka, RabbitMQ, etc.,
  58. Event Projection Closed Tab Opened Tab Open Tab Tab Opened

    Publish ReadModel Projection Client Listen Message Queue Tab Opened Kafka, RabbitMQ, etc.,
  59. Event Projection Closed Tab Opened Tab Open Tab Tab Opened

    Publish ReadModel Projection Client Listen Populate Message Queue Tab Opened Kafka, RabbitMQ, etc.,
  60. Event Projection Closed Tab Opened Tab Open Tab Tab Opened

    Publish ReadModel Projection Client Listen Populate Message Queue Tab Opened Kafka, RabbitMQ, etc.,
  61. Event Projection Closed Tab Opened Tab Open Tab Tab Opened

    Publish ReadModel Projection Client Listen Populate Query API Server Message Queue Tab Opened Kafka, RabbitMQ, etc.,
  62. Event Projection Closed Tab Opened Tab Open Tab Tab Opened

    Publish ReadModel Projection Client Listen Populate Query API Server Read Message Queue Tab Opened Kafka, RabbitMQ, etc.,
  63. Event Projection Closed Tab Opened Tab Open Tab Tab Opened

    Publish ReadModel Projection Client Listen Populate Query API Server Read Pull Message Queue Tab Opened Kafka, RabbitMQ, etc.,
  64. Event Projection Closed Tab Opened Tab Open Tab Tab Opened

    Publish ReadModel Projection Client Listen Populate Query API Server Read Pull Message Queue Tab Opened Kafka, RabbitMQ, etc.,
  65. Event Projection Closed Tab Opened Tab Open Tab Tab Opened

    Publish ReadModel Projection Client Listen Populate Query API Server Read Listen Pull Message Queue Tab Opened Kafka, RabbitMQ, etc.,
  66. Event Projection Closed Tab Opened Tab Open Tab Tab Opened

    Publish ReadModel Projection Client Listen Populate Query API Server Read WebSocket Client Listen Pull Message Queue Tab Opened Kafka, RabbitMQ, etc.,
  67. Event Projection Closed Tab Opened Tab Open Tab Tab Opened

    Publish ReadModel Projection Client Listen Populate Query API Server Read WebSocket Client Listen Push Pull Message Queue Tab Opened Kafka, RabbitMQ, etc.,
  68. Event Projection Closed Tab Opened Tab Open Tab Tab Opened

    Publish ReadModel Projection Client Listen Populate Query API Server Read WebSocket Client Listen Push Pull Listen Message Queue Tab Opened Kafka, RabbitMQ, etc.,
  69. Event Projection Closed Tab Opened Tab Open Tab Tab Opened

    Publish ReadModel Projection Client Listen Populate Query API Server Read WebSocket Client Listen Push Pull Data Analytics Client Listen Message Queue Tab Opened Kafka, RabbitMQ, etc.,
  70. Event Projection Closed Tab Opened Tab Open Tab Tab Opened

    Publish ReadModel Projection Client Listen Populate Query API Server Read WebSocket Client Listen Push Pull Data Analytics Client Listen Message Queue Tab Opened Kafka, RabbitMQ, etc.,
  71. Event Projection Closed Tab Opened Tab Open Tab Tab Opened

    Publish ReadModel Projection Client Listen Populate Query API Server Read WebSocket Client Listen Push Pull Data Analytics Client Listen Populate Message Queue Tab Opened Kafka, RabbitMQ, etc.,
  72. Event Projection Closed Tab Opened Tab Open Tab Tab Opened

    Publish ReadModel Projection Client Listen Populate Query API Server Read WebSocket Client Listen Push Pull Data Analytics Client Listen Populate Message Queue Tab Opened Kafka, RabbitMQ, etc.,
  73. Event Projection Closed Tab Opened Tab Open Tab Tab Opened

    Publish ReadModel Projection Client Listen Populate Query API Server Read WebSocket Client Listen Push Pull Data Analytics Client Listen Populate Message Queue Tab Opened Kafka, RabbitMQ, etc.,
  74. Event Projection Closed Tab Opened Tab Open Tab Tab Opened

    Publish ReadModel Projection Client Listen Populate Query API Server Read WebSocket Client Listen Push Pull Data Analytics Client Listen Populate Message Queue Tab Opened Kafka, RabbitMQ, etc., Uni directional Data flow (Flux?)
  75. Read Model Projection { "tables" : [{"id" : 1, "status"

    : "available"}] } Tab Opened { "tables" : [{"id" : 1, "status" : "waiting_for_order"}] }
  76. Read Model Projection { "tables" : [{"id" : 1, "status"

    : "available"}] } Tab Opened { "tables" : [{"id" : 1, "status" : "waiting_for_order"}] } Order Placed
  77. Read Model Projection { "tables" : [{"id" : 1, "status"

    : "available"}] } Tab Opened { "tables" : [{"id" : 1, "status" : "waiting_for_order"}] } Order Placed { "tables" : [{"id" : 1, "status" : "in_service"}] }
  78. Read Model Projection { "tables" : [{"id" : 1, "status"

    : "available"}] } Tab Opened { "tables" : [{"id" : 1, "status" : "waiting_for_order"}] } Order Placed { "tables" : [{"id" : 1, "status" : "in_service"}] } Order Served
  79. Read Model Projection { "tables" : [{"id" : 1, "status"

    : "available"}] } Tab Opened { "tables" : [{"id" : 1, "status" : "waiting_for_order"}] } Order Placed { "tables" : [{"id" : 1, "status" : "in_service"}] } Order Served
  80. Error Handling User may post an invalid command Fetching Events

    may fail Saving Events may fail type Result<'T,'E> = | Success of 'T | Error of 'E
  81. User may post an invalid command // Event list ->

    Command -> Event list let evolve = // ... // Command -> Event list let handleCommand command = let pastEvents = getTableId command |> getPastEvents evolve pastEvents command // State -> Command -> Event list let execute state command = let events = // ... events
  82. User may post an invalid command // Event list ->

    Command -> Event list let evolve = // ... // Command -> Event list let handleCommand command = let pastEvents = getTableId command |> getPastEvents evolve pastEvents command // State -> Command -> Event list let execute state command = let events = // ... events // State -> Command -> Result<Event list,string> let execute state command = match command with | OpenTab -> match state with | ClosedTab -> Success [TabOpened] | _ -> Error "Tab already opened" // ...
  83. User may post an invalid command // Event list ->

    Command -> Event list let evolve = // ... // Command -> Event list let handleCommand command = let pastEvents = getTableId command |> getPastEvents evolve pastEvents command // State -> Command -> Event list let execute state command = let events = // ... events // State -> Command -> Result<Event list,string> let execute state command = match command with | OpenTab -> match state with | ClosedTab -> Success [TabOpened] | _ -> Error "Tab already opened" // ... // Event list -> Command -> Result<Event list, string> let evolve = // ...
  84. User may post an invalid command // Event list ->

    Command -> Event list let evolve = // ... // Command -> Event list let handleCommand command = let pastEvents = getTableId command |> getPastEvents evolve pastEvents command // State -> Command -> Event list let execute state command = let events = // ... events // State -> Command -> Result<Event list,string> let execute state command = match command with | OpenTab -> match state with | ClosedTab -> Success [TabOpened] | _ -> Error "Tab already opened" // ... // Event list -> Command -> Result<Event list, string> let evolve = // ... // Command -> Result<Event list, string> let handleCommand command = // ...
  85. User may post an invalid command // HttpRequest -> HttpResponse

    let commandHandler httpRequest = let command = // get Command from HTTP request let newEvents = handleCommand command saveEvents newEvents // return OK response
  86. User may post an invalid command // HttpRequest -> HttpResponse

    let commandHandler httpRequest = let command = // get Command from HTTP request let newEvents = handleCommand command saveEvents newEvents // return OK response // HttpRequest -> HttpResponse let commandHandler httpRequest = let command = //... match handleCommand command with | Success newEvents -> saveEvents newEvents // return OK response | Error message -> // return BAD_REQUEST
  87. User may post an invalid command // HttpRequest -> HttpResponse

    let commandHandler httpRequest = let command = // get Command from HTTP request let newEvents = handleCommand command saveEvents newEvents // return OK response // HttpRequest -> HttpResponse let commandHandler httpRequest = let command = //... match handleCommand command with | Success newEvents -> saveEvents newEvents // return OK response | Error message -> // return BAD_REQUEST Fetching Events may fail Saving Events may fail
  88. User may post an invalid command // HttpRequest -> HttpResponse

    let commandHandler httpRequest = let command = // get Command from HTTP request let newEvents = handleCommand command saveEvents newEvents // return OK response // HttpRequest -> HttpResponse let commandHandler httpRequest = let command = //... match handleCommand command with | Success newEvents -> saveEvents newEvents // return OK response | Error message -> // return BAD_REQUEST Fetching Events may fail Saving Events may fail https://fsharpforfunandprofit.com/rop/
  89. Performance Tab Opened Order Placed Drink Served Food Prepared Food

    Served Order Served Tab Closed Do I need to fetch all the events to compute the state every time?
  90. Performance Tab Opened Order Placed Drink Served Food Prepared Food

    Served Order Served Tab Closed Do I need to fetch all the events to compute the state every time? Need not to be!
  91. Performance Tab Opened Order Placed Drink Served Food Prepared Food

    Served Order Served Tab Closed Do I need to fetch all the events to compute the state every time? Need not to be! Snapshots
  92. Parallel Update Optimistic Locking Tab Opened 0 Order Placed 1

    Drink Served 2 Food Prepared 3 Food Served 4
  93. It’s not a “Silver Bullet” Thinks To Consider CQRS and

    Event Sourcing are not top-level Architectures
  94. It’s not a “Silver Bullet” Thinks To Consider A whole

    system based on Event Sourcing is an Anti-Pattern CQRS and Event Sourcing are not top-level Architectures
  95. - ThoughtWorks Tech Radar 2012 F# is excellent at concisely

    expressing business and domain logic - http://fsharp.org/testimonials/