Top Banner
©2014 GlobalLogic Inc. CONFIDENTIAL
26

Introduction to CQRS (Command Query Responsibility Segregation)

Dec 01, 2014

Download

Engineering

This presentation is about Command Query Responsibility Segregation (CQRS), a small tactical pattern dealing with different optimization strategies for reads and writes. In other words, CQRS suggests separate models depending whether there is a Command or a Query.

Presentation by Oleksandr Loktyev (Team Lead, GlobalLogic, Lviv), delivered at Lviv .Net TechTalk, August 20, 2014.
More details -
http://www.globallogic.com.ua/press-releases/lviv-dotnet-techtalk-coverage
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Introduction to CQRS (Command Query Responsibility Segregation)

©2014 GlobalLogic Inc. CONFIDENTIAL

Page 2: Introduction to CQRS (Command Query Responsibility Segregation)

2 CONFIDENTIAL

Introduction to CQRS

Oleksandr Loktyev

Page 3: Introduction to CQRS (Command Query Responsibility Segregation)

3 CONFIDENTIAL

Command-query separation (CQS)

Introduction to CQRS

A method should either change the state of an object or return a result, but not both.

1. Queries. Return results.

2. Commands. Change state.

Pros

• Method intents are well understood

• No side effects

Page 4: Introduction to CQRS (Command Query Responsibility Segregation)

4 CONFIDENTIAL

Command query responsibility segregation (CQRS)

Introduction to CQRS

• A pattern based on CQS principle.

• Conceptual model is split into separate models depending whether it is a Command or Query.

Page 5: Introduction to CQRS (Command Query Responsibility Segregation)

5 CONFIDENTIALIntroduction to CQRS

CustomerService

Customer GetCustomer(CustomerId) CustomerSet GetCustomersWithName(Name) void CreateCustomer(Customer) void EditCustomerDetails(CustomerDetails)

Applying CQRS on this would result in two services:

CustomerServiceCommands

void CreateCustomer(Customer) void EditCustomerDetails(CustomerDetails)

CustomerServiceQueries

Customer GetCustomer(CustomerId) CustomerSet GetCustomersWithName(Name) 

Page 6: Introduction to CQRS (Command Query Responsibility Segregation)

6 CONFIDENTIALIntroduction to CQRS

And that’s it!

There is nothing more to it than that… 

Page 7: Introduction to CQRS (Command Query Responsibility Segregation)

7 CONFIDENTIAL

Typical web architecture

Introduction to CQRS

Page 8: Introduction to CQRS (Command Query Responsibility Segregation)

8 CONFIDENTIAL

Domain objects are natural for CrUD operations

Introduction to CQRS

public void Undismiss(DismissedObjectDTO dto)

{

var dismissedObject = _uow.DismissedObjectRepository.Get (dto.ObjectId, dto.ObjectTypeId);

dismissedObject.EndDate = DateTime.Now;

_uow.DismissedObjectRepository.Save(dismissedObject);

if (dismissedObject.ObjectType.ID == (int) Enums.CoachingObjectType.Observation)

{

var reviewDetail = _uow.EventReviewDetailDAO.Get(dto.ObjectId);

erd.ObservationScore = 100;

_uow.EventRepository.Save(erd);

}

_uow.CommitChanges();

}

Page 9: Introduction to CQRS (Command Query Responsibility Segregation)

9 CONFIDENTIAL

But can be extremely inefficient for reads

Introduction to CQRS

Lazy loading:

public Company GetCameraCompany(Camera camera)

{

return camera.Vehicle.Driver.Company;

}

Page 10: Introduction to CQRS (Command Query Responsibility Segregation)

10 CONFIDENTIAL

One more example

Introduction to CQRS

Incorrect fetching strategy.

private static void SomeOperation(List<Customer> customers)

{

foreach (var customer in customers)

{

foreach (var order in customer.Orders)

{

// do something

}

}

}

Page 11: Introduction to CQRS (Command Query Responsibility Segregation)

11 CONFIDENTIAL

Something that is more natural for Read operation

Introduction to CQRS

Plain data instead of Domain Model.

private static void SomeOperation(List<Customer> customers)

{

var customerOrderDTO = _uow.customerRepository.GetCustomerOrders(customers);

foreach (var order in customerOrderDTO .Orders)

{

// do something

}

}

Page 12: Introduction to CQRS (Command Query Responsibility Segregation)

12 CONFIDENTIAL

Queries

Introduction to CQRS

• What’s the purpose of queries? To show data. Not objects.

• So why should the data from the database come across 5 layers through 3 model transformations? It’s a bit overkill to display data.

• Why not just this: The UI read data from the database and displays it?

Page 13: Introduction to CQRS (Command Query Responsibility Segregation)

13 CONFIDENTIALIntroduction to CQRS

Consequence 1

Commands and queries use the same data but they should not necessarily use the same data model

Page 14: Introduction to CQRS (Command Query Responsibility Segregation)

14 CONFIDENTIAL

CQRS way

Introduction to CQRS

It is natural to use a different model to update information than the model you use to read information.

Page 15: Introduction to CQRS (Command Query Responsibility Segregation)

15 CONFIDENTIAL

Simple query for grid

Introduction to CQRS

SELECT

c.Name, o.Name, ot.Type

FROM Customer c

INNER JOIN CustomerOrder co ON co.CustomerId = c.CustomerId

INNER JOIN Order o ON co.OrderId = c.OrderId

INNER JOIN OrderType ot ON o.OrderId = ot.OrderId

WHERE

o.CustomerId = 20

AND ot.Type = ‘Active’

Page 16: Introduction to CQRS (Command Query Responsibility Segregation)

16 CONFIDENTIAL

What if the query is slow?

Introduction to CQRS

1. Execution plan and query optimization.

2. Add indexes.

3. Move to stored procedure.

4. Completely remove ORM.

The fact is that some queries simply cannot be quick.

Page 17: Introduction to CQRS (Command Query Responsibility Segregation)

17 CONFIDENTIAL

Let’s add denormalization

Introduction to CQRS

SELECT

CustomerName, OrderName, OrderType

FROM CustomerOrderView co

WHERE

CustomerId = 20

AND OrderType = ‘Active’

Page 18: Introduction to CQRS (Command Query Responsibility Segregation)

18 CONFIDENTIALIntroduction to CQRS

Consequence 2

Database can contain denormalized data for reads

Page 19: Introduction to CQRS (Command Query Responsibility Segregation)

19 CONFIDENTIAL

CQRS way

Introduction to CQRS

Queries tend to use denormalized data rather then classical database approach.

Page 20: Introduction to CQRS (Command Query Responsibility Segregation)

20 CONFIDENTIAL

Let’s go further and separate storages

Introduction to CQRS

Page 21: Introduction to CQRS (Command Query Responsibility Segregation)

21 CONFIDENTIAL

Read storage can be actually anything you want

Introduction to CQRS

Page 22: Introduction to CQRS (Command Query Responsibility Segregation)

22 CONFIDENTIAL

How to populate read storage? Synchronous way.

Introduction to CQRS

Page 23: Introduction to CQRS (Command Query Responsibility Segregation)

23 CONFIDENTIAL

How to populate read storage? Async way.

Introduction to CQRS

Page 24: Introduction to CQRS (Command Query Responsibility Segregation)

24 CONFIDENTIAL

CQRS is …

Introduction to CQRS

• CQRS is a small tactical pattern

• CQRS is learnable in 5 minutes

• CQRS can open many doors

Page 25: Introduction to CQRS (Command Query Responsibility Segregation)

25 CONFIDENTIALIntroduction to CQRS

Benefits• Handles domain complexity

• Applies different optimization strategies for reads and writes

• Scalability

When to use• Complex domains

• High performance applications

• Only on specific portions of a system (Bounded Context in DDD) 

Page 26: Introduction to CQRS (Command Query Responsibility Segregation)

26 CONFIDENTIAL

Questions?