Event Sourcing is a transferable skill

As developers we’re constantly learning to keep our axes sharp. Getting to know new concepts, patterns or paradigms broadens our horizons. It may eventually result in having new perspective how to solve business problems we’re facing.

Learning comes with a certain cost. It’s an investment we’re taking now to reap benefits from it in the future. In a longer or a shorter term. Can we always justify this cost? Will the thing we’ve learned be still useful in a year or two? Or after we’re forced to change the hammer — being it the framework or language we specialize in?

Is this whole Event Sourcing a skill worth learning?

Below you’ll find an example of Event Sourcing in Ruby. Give it a look.

class Product include AggregateRoot def register ( store_id :, sku :) apply ( ProductRegistered . new ( data: { store_id: store_id , sku: sku , })) end def supply ( quantity ) apply ( ProductSupplied . new ( data: { store_id: @store_id , sku: @sku , quantity: quantity , })) end def reserve ( quantity :, order_number :) unless @quantity_available >= quantity raise QuantityNotAvailable end apply ( ProductReserved . new ( data: { store_id: @store_id , sku: @sku , quantity: quantity , order_number: order_number , })) end private def apply_strategy -> ( _me , event ) { { ProductRegistered => method ( :registered ), ProductSupplied => method ( :supplied ), ProductReserved => method ( :reserved ), }. fetch ( event . class ). call ( event ) } end def registered ( event ) @store_id = event . data . fetch ( :store_id ) @sku = event . data . fetch ( :sku ) @quantity_available = 0 @quantity_reserved = 0 @quantity_shipped = 0 end def supplied ( event ) @quantity_available += event . data . fetch ( :quantity ) end def reserved ( event ) quantity = event . data . fetch ( :quantity ) @quantity_available -= quantity @quantity_reserved += quantity end end

This particular code uses aggregate_root gem. It’s really a detail — most of the implementations in imperative languages look alike. Compare to this one in C#. Once you get the idea right and maybe implement it yourself, you should be able to take this technique with you to a different language. Cool.

How would Event Sourcing look like in a completely different world than Ruby? Let’s say — Haskell:

module Inventory where type Sku = String type StoreId = String type Quantity = Integer type OrderNumber = String data Event = ProductRegistered Sku StoreId | ProductSupplied Sku StoreId Quantity | ProductReserved Sku StoreId OrderNumber Quantity data Command = Register Sku StoreId | Supply Quantity | Reserve Quantity OrderNumber data Product = Product { sku :: Sku , storeId :: StoreId , quantityAvailable :: Quantity , quantityReserved :: Quantity } handle :: [ Event ] -> Command -> [ Event ] handle events command = handle' product command where product = apply events handle' :: Maybe Product -> Command -> [ Event ] handle' product ( Register sku storeId ) = [ ProductRegistered sku storeId ] handle' ( Just product ) ( Supply quantity ) = [ ProductSupplied ( sku product ) ( storeId product ) quantity ] handle' ( Just product ) ( Reserve quantity orderNumber ) | notAvailable = error "quantity not available" | otherwise = [ ProductReserved ( sku product ) ( storeId product ) orderNumber quantity ] where notAvailable = ( quantityAvailable product ) < quantity handle' Nothing _ = error "Welp" apply :: [ Event ] -> Maybe Product apply events = foldl apply' Nothing events apply' :: Maybe Product -> Event -> Maybe Product apply' Nothing ( ProductRegistered sku storeId ) = Just ( Product sku storeId 0 0 ) apply' ( Just product ) ( ProductSupplied _ _ quantity ) = Just ( product { quantityAvailable = ( quantityAvailable product ) + quantity }) apply' ( Just product ) ( ProductReserved _ _ _ quantity ) = Just ( product { quantityAvailable = ( quantityAvailable product ) - quantity , quantityReserved = ( quantityReserved product ) + quantity })

Not bad, even given my so-so Haskell skills. Huge thanks to Tom Janssens for influence! There are different building blocks — sure. It will look alien at first sight if you’ve been only programming Ruby.

Still the idea is about taking action (described as Command), protected by the business rules (conditions).

handle' ( Just product ) ( Reserve quantity orderNumber ) | notAvailable = error "quantity not available" | otherwise = [ ProductReserved ( sku product ) ( storeId product ) orderNumber quantity ] where notAvailable = ( quantityAvailable product ) < quantity

Rules operate on state (product).

data Product = Product { sku :: Sku , storeId :: StoreId , quantityAvailable :: Quantity , quantityReserved :: Quantity }

State is constructed from facts in the past (described as Event).

apply :: [ Event ] -> Maybe Product apply events = foldl apply' Nothing events

Finally, the outcome of an action is just another event.

handle :: [ Event ] -> Command -> [ Event ]

In my opinion functional programming makes even sweeter foundation to implement Event Sourcing — a bit differently expressed.

The key point is however that Event Sourcing is a transferable skill. You can learn it once. The principles behind it still make sense after technology change. It’s a technique in your toolbox much broader than — let’s say ActiveRecord callbacks.