Switching your mindset

There’s more than CRUD

Mirosław Pragłowski / @mpraglowski


Legacy system

Legacy code: the code most tightly coupled to your revenue stream.


Legacy code is where the lifetime of the code is not coincident with the team lifetime.

@mfeathers at #xprolo

Honor legacy code. It exists because it is bringing value. We work on it because we want it to keep bringing value.


Some people call it legacy code. I like to call it revenue code.


Unsuccessful code doesn't survive long enough to become legacy! Legacy code is the sign of being successful.



Command Query Responsibility Segregation

CQRS is not a top level architecture

just a way to implement part of the system

Event Sourcing

CQRS could be used without ES,
ES without CQRS not



Execute command

f(aggregate, command) => events


f(state, event) => state

Process manager

f(state, event) => maybe(command)

First domain event

  RailsEventStore::Client.new.read_all_streams_forward(:head, 1)
  => ProductItemEvents::ProductItemSold
      @metadata={:timestamp=>2014-11-12 22:20:24 UTC},
      @data={:order_id=>23456, :product_item_id=>123456,
          "id"=>123456, "order_id"=>23456, "product_type_id"=>98765,
          "price"=>50, "barcode"=>"1234567890",
          "scanned_at"=>nil, "serialized_type"=>nil,
          "order_line_id"=>3456789, "code_id"=>nil,
          "updated_at"=>2014-11-12 22:20:24 UTC, "created_at"=>2014-11-12 22:20:24 UTC}}

Trials & errors

Anatomy of the Domain Event

Rule #1

the naming is hard, really hard

Rule #2

don’t be CRUDy

Rule #3

your event is not your entity

Rule #4

be explicit

Rule #5

natural is better

Rule #6

time is a modelling factor

Rule #7

when in doubt

First domain event

(done right)

=> TicketSold
     @metadata={:timestamp=>2014-11-12 22:20:24 UTC},
            :order=>{SaleIdentification value object},
            :type=>{Ticket type value object},
            :price=>{Price value object}}

Command & Queries

There is no such thing as async command

The command

Me: One more beer, please.

Bartender: Ok, here is your beer. (HTTP 200)

Bartender: Fuck off. You are drunk. (HTTP 403)

Another command

Me: One more beer, please.

Bartender: Ok, it will be delivered to your table. (HTTP 202)

Bartender: Sorry, we ran out of beer. (HTTP 404)

Both commands are sync

It does not matter if you actually get your beer or not.

They have different meaning.

Command is only for things that has not happened yet. If something has already happened then this is event.

1 command =/= 1 event

Sync vs async

Don't publish it yet

Beware of transactions

Consistency is overrated


Just deal with it

Compensation messages

Event versioning

Rewriting history

Only valid in some cases

Avoid race conditions

Memento pattern & upgrading events

Have your domain only deal with the “latest” version of the event


Bounded contexts

Event Storming

Polyglot data

Elastic Search

Reporting model based on star schema

External services / applications

Current mindset

Command is a entry to the system

Query fast & simple from denormalised,
tailored datastore

Domain events to mark all decisions made

Arkency's blog and YT



Robert's talk on Sagas


Robert's video on Bounded contexts


Andrzej's couse on DDD


Rails Event Store, Http Event Store



RailsDDD slack


Command's gem by Paweł



Available at: