Slide 1

Slide 1 text

(Neue Wege mit CQRS) Oliver Wolf CQRS for Great Good

Slide 2

Slide 2 text

Oliver Wolf @owolf www.innoQ.com @innoQ

Slide 3

Slide 3 text

CQRS Command Query Responsibility Segregation

Slide 4

Slide 4 text

The default architecture for distributed business apps Domain Model User Interface Remote Facade Application Services DTO DTO ORM DB findCustomers() getCustomer() updateCustomer() John Doe
...
...

Slide 5

Slide 5 text

The default architecture for distributed business apps Domain Model User Interface Remote Facade Application Services DTO DTO ORM DB GET /customers?filter=... GET /customer/{id} PUT /customer/{id} { "name": “John Doe”, "address": { ... } }

Slide 6

Slide 6 text

The default architecture for distributed business apps Domain Model User Interface Remote Facade Application Services DTO DTO ORM DB GET /customers?filter=... GET /customer/{id} PUT /customer/{id} { "name": “John Doe”, "address": { ... } } Anything wrong with this?

Slide 7

Slide 7 text

Maybe not.

Slide 8

Slide 8 text

Scalability?

Slide 9

Slide 9 text

Domain Model?

Slide 10

Slide 10 text

“The features that characterize a class are divided into commands and queries. A command serves to modify objects, a query to return information about objects.” Bertrand Meyer ETH Zurich cited from: Object-Oriented Software Construction, second edition, 1997

Slide 11

Slide 11 text

CQS Command Query Separation

Slide 12

Slide 12 text

Part of the Design-by-Contract methodology First demonstrated in the object-oriented EIFFEL programming language

Slide 13

Slide 13 text

class Foo { void command(); Result query(); } Mutates state Returns a value without causing side effects

Slide 14

Slide 14 text

CQRS = CQS in the large Scope is a single class Scope is a Bounded Context

Slide 15

Slide 15 text

interface CustomerService { void updateCustomer(Customer); CustomerList findCustomers(CustomerQuery); Customer getCustomer(ID); void deleteCustomer(ID); }

Slide 16

Slide 16 text

interface CustomerQueryService { CustomerList findCustomers(CustomerQuery); Customer getCustomer(ID); } interface CustomerCommandService { void updateCustomer(Customer); void deleteCustomer(ID); }

Slide 17

Slide 17 text

The default architecture for distributed business apps Domain Model User Interface Remote Facade Application Services DTO DTO ORM DB

Slide 18

Slide 18 text

The default architecture for distributed business apps Domain Model User Interface Query Facade Query Services DTO DTO ORM DB Command Facade Command Services CQRS PATTERN APPLIED

Slide 19

Slide 19 text

That’s it? You serious???

Slide 20

Slide 20 text

Yes, sorry.

Slide 21

Slide 21 text

The interesting thing about CQRS is not the pattern itself.

Slide 22

Slide 22 text

It’s damn simple, actually.

Slide 23

Slide 23 text

But it encourages you to challenge established assumptions and opens up new architectural options!

Slide 24

Slide 24 text

Unlearn what you have learned you must.

Slide 25

Slide 25 text

assumptions we often take for granted

Slide 26

Slide 26 text

Assumption 1: Reads and writes are strongly cohesive, so they must be part of the same Bounded Context.

Slide 27

Slide 27 text

Assumption 1: Reads and writes are strongly cohesive, so they must be part of the same Bounded Context. FALSE

Slide 28

Slide 28 text

The default architecture for distributed business apps Domain Model User Interface Query Facade Query Services DTO DTO ORM DB Command Facade Command Services CQRSified

Slide 29

Slide 29 text

The default architecture for distributed business apps CQRSified User Interface Query Facade Query Services DTO DTO ORM DB Command Facade Command Services Domain Model ORM Domain Model Query Facade Query Services ORM Domain Model Query Facade Query Services ORM Domain Model Command and query parts can scale independently, e.g. to accommodate highly asymmetric load.

Slide 30

Slide 30 text

Assumption 2: Reads and writes use the same data, so they must be served from and applied to the same domain model.

Slide 31

Slide 31 text

Assumption 2: Reads and writes use the same data, so they must be served from and applied to the same domain model. FALSE

Slide 32

Slide 32 text

The default architecture for distributed business apps Queries can benefit from a specialized query model, optimized for quick data retrieval (de-normalized, pre-aggregated,...) User Interface Query Facade Query Services DTO DTO ORM DB Command Facade Command Services Command Model ORM Domain Model Query Facade Query Services ORM Domain Model Query Facade Query Services ORM Query Model CQRSified

Slide 33

Slide 33 text

The default architecture for distributed business apps Queries can benefit from a specialized query model, optimized for quick data retrieval (de-normalized, pre-aggregated,...) User Interface Query Facade Query Services DTO DTO ORM DB Command Facade Command Services Command Model ORM Domain Model Query Facade Query Services ORM Domain Model Query Facade Query Services ORM Query Model ‣validate and process commands ‣keep data consistent ‣guarantee ACID properties ‣behaviour part of domain model ‣relatively difficult to scale out ‣rich query capabilities ‣short response times ‣different views on data ‣potentially denormalized ‣relatively easy to scale out CQRSified

Slide 34

Slide 34 text

Assumption 3: Even for queries, we have to go through the domain model to abstract from the underlying database model.

Slide 35

Slide 35 text

Assumption 3: Even for queries, we have to go through the domain model to abstract from the underlying database model. FALSE

Slide 36

Slide 36 text

Query Services Query Services Thin Read Layer User Interface Query Facade Query Services DTO DTO ORM DB Command Facade Command Services Command Model Query Facade Query Services Query Facade Query Services SELECT … FROM … WHERE ... The default architecture for distributed business apps Queries are just dealing with data, not with behaviour. What do we need objects for? CQRSified

Slide 37

Slide 37 text

Query Services Query Services Thin Read Layer User Interface Query Facade Query Services DTO DTO ORM DB Command Facade Command Services Command Model Query Facade Query Services Query Facade Query Services SELECT … FROM … WHERE ... The default architecture for distributed business apps Queries are just dealing with data, not with behaviour. What do we need objects for? CQRSified Introduce thin read layer that makes optimized use of the database’s query capabilities No ORM, no fuss – just plain SQL (SQL happens to be really good at queries, you know...)

Slide 38

Slide 38 text

Assumption 4: We must use the same database for queries and commands to make sure that data is consistent.

Slide 39

Slide 39 text

Assumption 4: We must use the same database for queries and commands to make sure that data is consistent. FALSE

Slide 40

Slide 40 text

The default architecture for distributed business apps In many cases, eventual consistency is sufficient. The data users are looking at in the UI is always stale to some extent. Query Services Query Services Thin Read Layer User Interface Query Facade Query Services DTO DTO ORM DB Command Facade Command Services Command Model Query Facade Query Services Query Facade Query Services SELECT … FROM … WHERE ... Query DB Query DB Query DB Event Handler Event Handler Event Handler Events Write CQRSified

Slide 41

Slide 41 text

The default architecture for distributed business apps In many cases, eventual consistency is sufficient. The data users are looking at in the UI is always stale to some extent. Query Services Query Services Thin Read Layer User Interface Query Facade Query Services DTO DTO ORM DB Command Facade Command Services Command Model Query Facade Query Services Query Facade Query Services SELECT … FROM … WHERE ... Query DB Query DB Query DB Event Handler Event Handler Event Handler Events Write CQRSified Separate query DB, not necessarily relational Command model emits events when data changes Event handlers process events and update query DB asynchronously

Slide 42

Slide 42 text

Assumption 5: Commands must be processed immediately to ensure data consistency.

Slide 43

Slide 43 text

Assumption 5: Commands must be processed immediately to ensure data consistency. FALSE

Slide 44

Slide 44 text

The default architecture for distributed business apps In many cases, users don’t care if their actions have immediate effect – as long as they eventually get feedback. Query Services Query Services Thin Read Layer User Interface Query Facade Query Services CMD DTO ORM DB Command Facade Command Services Command Model Query Facade Query Services Query Facade Query Services SELECT … FROM … WHERE ... Query DB Query DB Query DB Event Handler Event Handler Event Handler Events Write Command Queue Commands CQRSified

Slide 45

Slide 45 text

The default architecture for distributed business apps In many cases, users don’t care if their actions have immediate effect – as long as they eventually get feedback. Query Services Query Services Thin Read Layer User Interface Query Facade Query Services CMD DTO ORM DB Command Facade Command Services Command Model Query Facade Query Services Query Facade Query Services SELECT … FROM … WHERE ... Query DB Query DB Query DB Event Handler Event Handler Event Handler Events Write Command Queue Commands CQRSified Decouple user interaction and command processing Give visual feedback and allow users to check processing progress (and result)

Slide 46

Slide 46 text

Assumption 6: The current state of domain objects must be persistent.

Slide 47

Slide 47 text

Assumption 6: The current state of domain objects must be persistent. FALSE

Slide 48

Slide 48 text

Query Services Query Services Thin Read Layer User Interface Query Facade Query Services CMD DTO DB Command Facade Command Services Command Model Query Facade Query Services Query Facade Query Services SELECT … FROM … WHERE ... Query DB Query DB Query DB Event Handler Event Handler Event Handler Events Write Command Queue Commands Processor The default architecture for distributed business apps CQRS plays well with an Event Sourcing architecture – you just store events and re-create the state of domain objects as needed. CQRSified

Slide 49

Slide 49 text

Query Services Query Services Thin Read Layer User Interface Query Facade Query Services CMD DTO DB Command Facade Command Services Command Model Query Facade Query Services Query Facade Query Services SELECT … FROM … WHERE ... Query DB Query DB Query DB Event Handler Event Handler Event Handler Events Write Command Queue Commands Processor The default architecture for distributed business apps CQRS plays well with an Event Sourcing architecture – you just store events and re-create the state of domain objects as needed. Events can always be replayed from event store CQRSified Model is strictly in- memory DB holds events, not state

Slide 50

Slide 50 text

‣ capture each update to application state in an event ‣ changes to domain objects are the result of applying events ‣ events are immutable ‣ events are a representation of what has happened at a specific time Event Sourcing in a nutshell

Slide 51

Slide 51 text

‣ allows you to rebuild application state at any point in time just by replaying events from t0 up to that point in time ‣ allows you to analyse historic data based on detailed events that would otherwise have been lost ‣ gives you an audit log “for free” ‣ you can add new, optimized read models (potentially in-memory) later without migration hassle and such What’s so great about Event Sourcing?

Slide 52

Slide 52 text

http://www.flickr.com/photos/kaptainkobold/5170454747/ How do I convince my boss that we’ll have to rewrite our application with CQRS???

Slide 53

Slide 53 text

Chances are you don’t.

Slide 54

Slide 54 text

CQRS is not a silver bullet and doesn’t apply everywhere. Beware of the added complexity!

Slide 55

Slide 55 text

Don’t do CQRS… …if your application is just a simple CRUD-style app. …if you don’t have scaling issues. …if it doesn’t help improve your domain models.

Slide 56

Slide 56 text

Consider doing CQRS… …if your write/read load ratio is highly asymmetrical. …if scaling your application is difficult. …if your domain model is bloated by complex domain logic, making queries inefficient. …if you can benefit from event sourcing.

Slide 57

Slide 57 text

Frameworks, any?

Slide 58

Slide 58 text

Axon Framework (Java) www.axonframework.org Piotr Wyczesany Lokad (.NET) http://lokad.github.com/lokad-cqrs/ Piotr Wyczesany …and some more Piotr Wyczesany

Slide 59

Slide 59 text

www.axonframework.org

Slide 60

Slide 60 text

Apache 2 license Version 2.0 released earlier this year Maintained by Trifork Netherlands Commercial support offering available

Slide 61

Slide 61 text

No content

Slide 62

Slide 62 text

Distributed Event Bus, based on ‣JGroup ‣Disruptor ‣AMQP ‣Spring Integration ‣File system ‣JPA ‣MongoDB ‣Cassandra ‣Redis ‣Google App Engine DataStore Supports both state persistence (via JPA) and event sourcing

Slide 63

Slide 63 text

‣ relatively unobtrusive, commands and events are just Java objects ‣ Event sourcing is not mandatory, state persistence is still supported ‣ Support for multiple EventBus and EventStore implementations ‣ Integrates nicely with Spring ‣ supports complex business transactions (“sagas” in DDD parlance) Things I like about Axon

Slide 64

Slide 64 text

‣ requires some familiarity with DDD terms (you should at least know what an Aggregate is) ‣ Axon doesn’t try to hide CQRS from developers – whether this good or bad depends on experience and knowledge about CQRS Things I’m not quite sure about

Slide 65

Slide 65 text

That’s all I have. Feel free to ask me anything! @owolf