Skip to content

RailsEventStore/aggregates

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Aggregates

An experiment of different aggregate implementations. All implementations must pass same test suite: arranged with commands, asserted with events.

Experiment subject

Quite typical workflow of an issue in a popular task tracking software (Jira).

workflow

Existing experiments

Classical example

source

  • probably most recognized implementation (appeared in Greg Young's CQRS example)
  • does not expose its internal state via reader methods
  • testability without persistence (just check if operation yields correct event)

Module source: https://github.com/RailsEventStore/rails_event_store/tree/5378b343dbf427f5ea68f7ddfc66d6a449a6ff82/aggregate_root/lib

Aggregate with exposed queries

source

  • clear separation of state sourcing (with projection)
  • aggregate not aware of events
  • handler queries aggregate whether particular action is possible

Aggregate with extracted state

source

  • aggregate initialized with already sourced state

Functional aggregate

source

  • no single aggregate, just functions that take state and return events

Polymorphic

source

  • domain classes per each state
  • no messaging in domain classes
  • no id in domain class
  • invalid state transition cared by raising exception

More: https://blog.arkency.com/make-your-ruby-code-more-modular-and-functional-with-polymorphic-aggregate-classes/

Duck typing

source

  • domain classes per each state
  • no messaging in domain classes
  • no id in domain class
  • invalid state transition cared by not having such methods on objects (duck)

Aggregate with yield

source

  • yield is used to publish events (no unpublished_events in aggregate)
  • aggregate repository separated from logic

Aggregate with repository

source

  • aggregate is unware of infrastructure
  • aggregate can built itself from events (but it could be recreated in any way)
  • aggregate keeps the state in PORO way
  • aggregate registers events aka changes
  • aggregate provides API to read registered events
  • Infrastructure (through repository in this case) is responsible for building/saving the aggregate so it could be done in any way - Event Sourcing, serialization etc

Roles/DCI

source

  • better mental model by not having separate classes per state
  • one object which changes roles
  • extend(Role.clone) is used as Ruby ignores subsequent extend with the same module

PORO with attributes

source

  • clear separation of state sourcing (with projection)
  • aggregate not aware of events
  • aggregate object is still responsible for holding invariants
  • no id in domain class

Decider

source

  • clear separation of state sourcing (with projection)
  • aggregate with decider pattern

Decider with decide.rb gem

source

  • clear separation of state sourcing (with projection) with expected version
  • aggregate with decider pattern and decide.rb DSL
  • mapping between infra (RES) events and domain events used inside decider

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 7