Event Sourcing for Functional

by Daniel Westheide / @kaffeecoder

@ flatMap(Oslo), 14.05.2013

Example application


git clone git://github.com/dwestheide/eventhub-flatmap2013.git
cd eventhub-flatmap2013
git checkout step-0
sbt run

Principles of Functional Programming

Immutable data

case class Meeting(
    id: MeetingId,
    name: String,
    time: DateTime,
    venue: Venue)

Pure functions

def moveToVenue(meeting: Meeting, newVenue: Venue): Meeting =
  meeting.copy(venue = newVenue)

Updating application state

meetingRepo.fromIdentity(meetingId).foreach { meeting =>
Wait, so our application state is effectively mutable? Doh!


In my domain, it is not important to know the previous states of an entity.
If my domain requires a history of what happened, of course I explicitly make that part of my domain model.

Event Sourcing


  • A cluster of related objects, both entities and value objects
  • One of the entities is the Aggregate Root
  • Only the root can be referenced from outside the aggregate


  • A boundary for transactional consistency
  • Must ensure that its state never ever violates its business invariants
  • Outside its boundary, there can only be eventual consistency
  • Only one aggregate can be modified in a single transaction


Event Sourcing

  • Every state-modifying operation on an aggregate results in an event
  • The actual state change is achieved by applying the event to the aggregate

Producing events for state changes

def moveToVenue(
    meeting: Meeting,
    venue: Venue): Validation[String, (MeetingEvent, Meeting)] =
  if (canMoveToVenue(meeting, venue)) {
    val event = MovedToVenue(new DateTime(), meeting.id, venue)
    (event, this(meeting, event)).success
  } else s"Cannot move $meeting to $venue".fail

Applying an event

              (Aggregate, DomainEvent) => Aggregate

Applying an event

def apply(meeting: Meeting, event: MeetingEvent): Meeting =
  event match {
    case VenueChanged(_, _, aVenue) =>
      meeting.copy(venue = aVenue)

Event Stream

Building up current state

def currentState(meetingId: MeetingId): Meeting =

Can't change what was...


  • Audit log for free
  • Analysis of historic data
  • Replaying events to examine errors
  • Flexibility: arbitrary new views or queries (with CQRS)
  • Enables Memory Image


Command-Query Responsibility Segregation


  • Command model: Validates and processes commands
  • Query model: various views on the data, denormalized
  • Can be scaled independently

CQRS with Event Sourcing

Memory Image

  • Keep application state in memory
  • Rebuild application state from event store
  • Aggregates in STM Refs

Single Writer Principle

Only a single service can process commands on an aggregate

See Single Writer Principle by Martin Thompson

Maybe we can use actors?

  • Event-driven
  • Can keep state
  • Process incoming messages one after another


Building blocks

  • Processor
  • Channel
  • Journal

Let's get our hands dirty...