cqrs and what it means for your architecture

65
CQRS Separating your peas from your potatoes tp://richard-banks.org, @rbanks54

Upload: richard-banks

Post on 16-Apr-2017

1.563 views

Category:

Software


3 download

TRANSCRIPT

Page 1: CQRS and what it means for your architecture

CQRS Separating your peas from your

potatoes

http://richard-banks.org, @rbanks54

Page 2: CQRS and what it means for your architecture

CommandQuery

ResponsibilitySeparation

Page 3: CQRS and what it means for your architecture

Commands– update state, no return value

Queries– read state, return data

- no side effects

Page 4: CQRS and what it means for your architecture

Example: HTTP Verbs

Page 5: CQRS and what it means for your architecture

Queries---

GETHEAD

OPTIONSTRACE

Page 6: CQRS and what it means for your architecture

Commands---

PUTPOSTPATCH

DELETE

Page 7: CQRS and what it means for your architecture

By the way,

is it CQS or CQRS?

Page 8: CQRS and what it means for your architecture

CQS = Command Query Separation

In one class, have separate methods for changing and reading state

Page 9: CQRS and what it means for your architecture

public class UserAccount{ //...

public bool IsActive { get; private set; }

public void Activate() { IsActive = true; }

public void DeActivate() { IsActive = false; }}

Query

Command

Command

Page 10: CQRS and what it means for your architecture

CQRS

Have separate classes for changing and reading state

Page 11: CQRS and what it means for your architecture

public class UserAccount{ //Only change state of the object via methods within the class //State changing methods are marked internal

public bool IsActive { get; private set; }

internal void Activate() { IsActive = true; }

internal void DeActivate() { IsActive = false; }}

Page 12: CQRS and what it means for your architecture

public class AccountQueryService{ IQueryable<UserAccount> db; public AccountQueryService(IQueryable<UserAccount> db) { this.db = db; }

public UserAccount FindByName(string accountName) { return db.Where(a => a.Name.Equals(accountName)).Single(); }

public IEnumerable<UserAccount> ActiveAccounts() { return db.All(a => a.IsActive); }}

Anti Pattern in use for simplicity of sample code

Should return just the data needed, not a domain object

Page 13: CQRS and what it means for your architecture

public class AccountCommandHandler{ AccountQueryService view; ILogger logger;

public AccountCommandHandler(AccountQueryService view, ILogger logger) { this.view = view; this.logger = logger; }

public void ActivateAccount(string accountName) { try

{ var account = view.FindByName(accountName); account.Activate(); } catch { logger.Log("oops!"); throw; } logger.Log("Account activated..."); }}

Page 14: CQRS and what it means for your architecture

Possible first reaction?Whoa! Lots more code!!

Yes. Though it’s more expressive and intentional too.

Page 15: CQRS and what it means for your architecture

Question:

Where should persistence calls occur?

Page 16: CQRS and what it means for your architecture

MVC/API Controller?

In the UserAccount class?

Elsewhere?

Page 17: CQRS and what it means for your architecture

public class AccountCommandHandler{ //… public void ActivateAccount(string accountName) { try { var account = view.FindByName(accountName); account.Activate(); db.Save(account); } catch { logger.Log("oops!"); throw; } logger.Log("Account activated..."); }}

Page 18: CQRS and what it means for your architecture

Can we use query objects instead of query services? Sure!

Page 19: CQRS and what it means for your architecture

public class ActiveAccountsQuery : IQuery{ IQueryable<UserAccount> db; public ActiveAccountsQuery(IQueryable<UserAccount> db) { this.db = db; }

public IEnumerable<UserAccount> Execute() { return db.All(a => a.IsActive).ToList(); }}

Page 20: CQRS and what it means for your architecture

Question:

Should we drop the .Activate() and .DeActivate() methods from

the UserAccount class?

Page 21: CQRS and what it means for your architecture

public class UserAccount{ //Hello, anaemic domain model!

public bool IsActive { get; internal set; }}

Page 22: CQRS and what it means for your architecture

Is an Anaemic Domain Model OK?

Consultant answer: It Depends!

Page 23: CQRS and what it means for your architecture

Consider:

Are we building a CRUD app?

What happens when business rules change?

Page 24: CQRS and what it means for your architecture

public class UserAccount{ private string EmailValidated { get; private set; } public bool IsActive { get; private set; }

internal void Activate() { if (!EmailValidated) throw new ApplicationException("email is not yet verified"); IsActive = true; }

internal void DeActivate() { IsActive = false; }}

Behaviour change implemented in the

domain entity

No changes needed anywhere else

Page 25: CQRS and what it means for your architecture

Design Principles

Page 26: CQRS and what it means for your architecture

Separation of Concerns,Single Responsibility

Page 27: CQRS and what it means for your architecture

Domain Classes are responsible for their behaviours

(Avoid the anaemic domain model)

Page 28: CQRS and what it means for your architecture

Command Handlers are responsible for coordinating state

changes

(use repositories to persist those changes)

Page 29: CQRS and what it means for your architecture

Query Objects are responsible for retrieving data in a shape the

consumer wants.

(Completely avoids calling the domain)

Page 30: CQRS and what it means for your architecture

What’s this mean for my architecture?

Page 31: CQRS and what it means for your architecture

UI Application Domain Data

Commands

UI Application Data

Queries

Page 32: CQRS and what it means for your architecture

Command Services/Handlers

UI

Commands

Domain Model

Repositories

DatabaseQuery Store

Query Service

Data Access Layer

Projections

Queries Business Actions

Changes

Query Store

No O/R conversions

Describes the user’s

intent

Optimized for querying

Synchronous or asynchronous

updates Can simply be

denormalised tables in the main DB

Page 33: CQRS and what it means for your architecture

Commands

Page 34: CQRS and what it means for your architecture

A command should describea single user intention

against a single domain entity

e.g. OpenAccount,ResetAccountPassword

DisableAccount

Page 35: CQRS and what it means for your architecture

Thinking about commands and objects leads us towards…

Domain Driven Design

Page 36: CQRS and what it means for your architecture

High level DDD Concepts:

Entity: discrete lifecycle and identity

Value Object: no lifecycle, identified only by attribute values.

Aggregate: one or more entities and value objects,clustered together as a coherent whole.

Agg. Root: single entity that controls access to otherobjects in the aggregate

Context: setting in which a word has specific meaning (e.g ‘account’)

Page 37: CQRS and what it means for your architecture

Define modules in your app based on your Domain Contexts.

Page 38: CQRS and what it means for your architecture

Commands act on theAggregate Roots in your Context

Page 39: CQRS and what it means for your architecture

Queries

Page 40: CQRS and what it means for your architecture

Queries just need to get data.

So why go via the domain model?

Page 41: CQRS and what it means for your architecture

UI Application Domain Data

Commands

UI Application Data

Queries

Page 42: CQRS and what it means for your architecture

Why not de-normalise our datato optimise for reads?

Why not store it in a different database?

Page 43: CQRS and what it means for your architecture

Question:

If we split the storage of our domain data and our denormalised data…

How do we keep things in sync?

Page 44: CQRS and what it means for your architecture

We could keep the data on the same DB server…

…and use transactions/triggers to update multiple tables at

once.

Page 45: CQRS and what it means for your architecture

Or we could think about eventual consistency.

(Note: This is not required for CQRS)

Page 46: CQRS and what it means for your architecture

When a Domain Entity changes state, raise a Domain Event to

describe what happened.

Page 47: CQRS and what it means for your architecture

These Domain Events can be treated as messages and

published on a message bus

Page 48: CQRS and what it means for your architecture

Event Handlers subscribe to the events and update denormalised

views of data.

Makes transactions simpler.Must consider the impact of Eventual

Consistency on our users.

Page 49: CQRS and what it means for your architecture

Publishing Domain Events can lead to thinking about Event

Sourcing.

Note: Event Sourcing is NOT REQUIRED for CQRS

Page 50: CQRS and what it means for your architecture

Commands and Queries will likely lead to a Task based UI approach.

Page 51: CQRS and what it means for your architecture

What’s the catch?

Page 52: CQRS and what it means for your architecture

CQRS means you’ll need to think about design and your domain

model.

Page 53: CQRS and what it means for your architecture

It’s not needed for CRUDdy, “forms over data” applications

Page 54: CQRS and what it means for your architecture

Commands are not “fire and forget”.

You need to think about concurrency and exception

handling.

Page 55: CQRS and what it means for your architecture

You need to decide how to denormalize data.

Eventual consistency is not simple.

Page 56: CQRS and what it means for your architecture

It’s easy to fall back into old habits

Page 57: CQRS and what it means for your architecture

It’s hard to add to a legacy system

Page 58: CQRS and what it means for your architecture

It’s complexity you might not need.

Apply the YAGNI rule.

Page 59: CQRS and what it means for your architecture

So Why Use It Then?

Page 60: CQRS and what it means for your architecture

You have a complex domain model

Page 61: CQRS and what it means for your architecture

You have a scalability or performance problem

Page 62: CQRS and what it means for your architecture

You’re building a task based UI

Page 63: CQRS and what it means for your architecture

You have a collaborative domain model

Think, concurrent partial updates of the same entity by multiple people

Page 64: CQRS and what it means for your architecture

OK. We’re Done!

Want some references?

Page 65: CQRS and what it means for your architecture

MS Patterns & Practices, CQRS Journey: http://cqrsjourney.github.io/

Greg Youngs CRQS and Event Sourcing demo app: https://github.com/gregoryyoung/m-r

NCQRS Framework: https://github.com/pjvds/ncqrs

CQRS FAQ: http://www.cqrs.nu/Faq/command-query-responsibility-segregation

Effective Aggregate Design: http://dddcommunity.org/library/vernon_2011/

CQRS Myths: https://lostechies.com/jimmybogard/2012/08/22/busting-some-cqrs-myths/

Task based UIs: https://cqrs.wordpress.com/documents/task-based-ui/