Post on 14-May-2015
description
transcript
Greenfield Development with CQRS
David HoersterCo-Founder and CTO, BrainCredits
About Me
C# MVP (April 2011) Co-Founder of BrainCredits
(braincredits.com) Senior Technical Director for Resources
Global Professionals President of Pittsburgh .NET Users Group Organizer of recent Pittsburgh Code Camps Twitter - @DavidHoerster Blog –
http://geekswithblogs.net/DavidHoerster Email – david@braincredits.com
Goals
Understanding the CQRS Architecture & Benefits (& Drawbacks) Commands Domain Objects Events Handlers
Incorporating into Azure Queues and Blobs
Fronting it with MVC
Pre-Requisites
Some knowledge and familiarity with Domain Driven Design
Some knowledge of Azure objects Some knowledge of ASP.NET MVC Leaving the notion that your data
store must be normalized to the Nth degree at the door
Backstory
Goals for BrainCredits.com Fast reads Scalable Handle, potentially, large volumes of
requests Be able to change quickly Ability to track user in system and events
that occur Easy to deploy, manage Inexpensive (FREE????)
Backstory
Decided to jump into cloud with Azure BizSpark company Hey, it’s the cloud! Scalability Deployment via VS2010 Pretty inexpensive – no HW to manage But how to store data and design
system?
Backstory
I would recommend to start looking along the CQRS style of architectures- Rinat Abdullin
Articles by Greg Young, Udi Dahan, J. Oliver, R. Abdullin
Traditional ArchitectureIssues Get all of the orders for user “David”
in last 30 days
Customer (SalesLT)CustomerID
NameStyle
Title
FirstName
MiddleName
LastName
Suffix
CompanyName
SalesPerson
EmailAddress
Product (SalesLT)ProductID
Name
ProductNumber
Color
StandardCost
ListPrice
Size
Weight
ProductCategoryID
ProductModelID
SellStartDate
SellEndDate
ProductCategory (SalesLT)ProductCategoryID
ParentProductCategoryID
Name
rowguid
ModifiedDate
ProductModel (SalesLT)ProductModelID
Name
CatalogDescription
rowguid
ModifiedDate
SalesOrderDetail (SalesLT)SalesOrderID
SalesOrderDetailID
OrderQty
ProductID
UnitPrice
UnitPriceDiscount
LineTotal
rowguid
ModifiedDate
SalesOrderHeader (SalesLT)SalesOrderID
RevisionNumber
OrderDate
DueDate
ShipDate
Status
OnlineOrderFlag
SalesOrderNumber
PurchaseOrderNumber
AccountNumber
CustomerID
ShipToAddressID
BillToAddressID
ShipMethod
CreditCardApprovalCode
SubTotal
TaxAmt
Freight
Traditional ArchitectureIssues
Get all the orders for user ‘David’ in last 30 days
SELECT c.FirstName, c.MiddleName, c.LastName, soh.SalesOrderID, soh.OrderDate, sod.UnitPrice, sod.OrderQty, sod.LineTotal, p.Name as 'ProductName', p.Color, p.ProductNumber, pm.Name as 'ProductModel', pc.Name as 'ProductCategory', pcParent.Name as 'ProductParentCategory'FROM SalesLT.Customer c INNER JOIN SalesLT.SalesOrderHeader soh
ON c.CustomerID = soh.CustomerIDINNER JOIN SalesLT.SalesOrderDetail sod ON soh.SalesOrderID =
sod.SalesOrderIDINNER JOIN SalesLT.Product p ON sod.ProductID = p.ProductIDINNER JOIN SalesLT.ProductModel pm ON p.ProductModelID =
pm.ProductModelIDINNER JOIN SalesLT.ProductCategory pc ON p.ProductCategoryID =
pc.ProductCategoryIDINNER JOIN SalesLT.ProductCategory pcParent ON
pc.ParentProductCategoryID = pcParent.ProductCategoryIDWHERE c.FirstName = 'David'
AND soh.OrderDate > (GETDATE()-30)
Traditional ArchitectureIssues
Wouldn’t it be great if it was something like?SELECT FirstName, MiddleName, LastName, SalesOrderID, OrderDate, UnitPrice, OrderQty, LineTotal, ProductName, Color, ProductNumber, ProductModel, ProductCategory, ProductParentCategoryFROM CustomerSalesWHERE FirstName = 'David'
AND OrderDate > (GETDATE()-30)
Traditional ArchitecureIssues
It seems that many applications cater to fast C-U-D operations, but the Reads suffer Highly normalized databases Updating a Product Name is easy
What would make querying faster? Reducing JOINS Flattening out our model Heresy!
Business logic and domain objects bleed through layers as a result, too.
What Alternatives Are There?
That’s where CQRS may be an option Provides for fast reads at the ‘expense’ of more
expensive writes Once the data is read by the client, it’s already old▪ A system that is eventually consistent is usually
acceptable▪ EVENTUAL CONSISTENCY!▪ The read model for the system eventually is consistent with the
system events
Allows for scalability very easily▪ Even in Azure!
Encapsulates business logic in the domain▪ Adheres strictly to CQS
What is CQRS
Command Query Responsibility Segregation Based upon Bertrand Meyer’s Command
Query Separation principle:“every method should either be a command that performs an action, or a query that returns data to the caller, but not both. In other words, asking a question should not change the answer” (Meyer)
In essence, commands return acknowledgement; queries return data.
What is CQRS
Taking this further, CQRS describes an architecture where commands are messages (possibly asynchronous) queries go against a read model
Since commands are returning void, it allows for the message to be transformed into the read model If we’re transforming the message, why not make the read
model as fast as possible? Since we’re transforming the message, perhaps we can
take a few extra ticks for additional processing This flips the conventional wisdom of fast writes and
slow reads Now we have fast reads and “slower” writes (since we’re
writing to a denormalized store)
What is CQRS
CQRS essentially splits your application into two parts The Read Side The Command Side
The Read Side requests data and receives it
The Command Side issues commands (inserts, updates, deletes) and receives just an acknowledgment that it was received.
What is CQRS (Simplified)
Client
Read Model Store
Event Store
Repository Command Service
Domain (ARs)
Denormalizer
Event Handler
Command Issued – ack/nackData Requested/Returned
Command SideQuery Side
Getting Started
Steps on the Command Side Command is issued Routed to proper Domain object method Domain raises zero, one or more Events Events handled by Denormalizer to
persist data to read model Each step is really one or more
messages being sent
Getting Started
You can roll your own, or use a framework
Several out there, including: NCQRS Lokad.CQRS Agr.CQRS on CodePlex (not much
activity) Axon (Java)
By using a framework, there are “extras”
CQRS Frameworks
With NCQRS (ncqrs.org), you get: CQRS support Event Sourcing Support for SQL or NoSQL event sourcing Snapshotting
Not always good things If you’re doing ‘pure’ or ‘true’ CQRS, then this is
good Otherwise, may be overkill
Don’t depend on the framework Let the framework help you, not constrict you
Demo – In Which David Turns To A Life-Long Desire – Buzzword Bingo
Demo – BuzzyGo
Command Side Flow
Command Domain
Event 1
Event 2
Event N
Handler 1
Handler 2
Handler N
ReadMode
l
Commands
Simple message from the client to the back-end requesting something to be done
Imperative tone CreateUser DeleteCard MarkSquare
Contains enough information for the back-end to process the request
No return value Maps to Aggregate Root’s constructor or
method
Domain
Command maps to a AR method/ctor Business logic happens here
May assume validation done on client, but can be done here
Business rules applied here▪ e.g. FREE space is in the middle and is automatically marked.
Once business rules applied, data is added to events that are applied. One or more events can be applied
Once event is applied, domain updates itself and is added to the event source repository
Not exposed to client, generally
Events
Simple messages from domain Similar to commands
But not the same Semantically different CardCreated; SquareMarked; CardWon
Has enough information for event handler to write information to the read model
Denormalizer (Handler)
Handles the events applied by the domain
Should NOT perform any validation or business rules
Its job is to perform minimal projections and transformations of data and then send that data to the repository/datastore
Repository/DataStore being updated is the read model
Read Side Flow
ReadModel
Query Provider(Repo/
WCFDS/etc)
Client
Request for Data
DTO
Query
Results
Where Can I Use CQRS?
Windows apps Services Web apps Cloud-based apps Really doesn’t matter
Just depends on the problem being solved
CQRS in the Cloud
Hosting CQRS in Azure Really no different on the web side than
a CQRS web app Typically, you’d want 2 roles
Web Role for the UI, which also performs querying
Worker Role for the Command handling Both roles can scale out as much as
needed Multiple web roles with a single worker
role, or vice versa or both!
Communication in theCloud
How do I issue commands from my web role? 2 typical solutions▪ WCF service on the worker role side▪ Use Azure storage features (blobs, queues, tables)
Both have advantages and disadvantages▪ WCF is by default synchronous, so you’ll need to
design for fire-and-forget▪ But can be easier to get up and running quickly
▪ Azure Storage has a lot of moving pieces▪ Watch out for transaction costs!
Using Azure Storage
General flow is this Web role issues a command by dropping
it in a blob container (name is GUID). Command blob name is then dropped in
a queue Worker role monitors queue for work When it finds a message in the queue, it
grabs blob from storage based on id in queue message
Deserializes command and then sends it through normal CQRS pipeline
CQRS in the Cloud
Controller
Queue
Blob Storage
Command
HandlerAzure Table
Storage
Domain
Event(s)
Denormalizer
Read Model
Repository
CQRS in the Cloud
ASP.NET MVC Controller Reading data is no different, going
through a Repository Writing data (issuing commands)
involves dropping command into Azure Queue
CloudHelper class facilitates this▪ Also provides LogMessage facility
CQRS in the Cloud
Using Azure Table Storage for logging user actions… Different than events. Want to know user
behavior. Storage is huge – just watch transaction costs▪ Consider batching log reads
But you can create replays of user interaction▪ Similar to event sourcing’s replay of events▪ Event sourcing doesn’t capture “Cancels” or
“Reads”, which may be useful from a marketing perspective
Claim Credit for thisSession
BrainCreditshttp://www.braincredits.com/Lesson/16852
Resources
CQRS Info Site – http://cqrsinfo.com NCQRS Site –http://ncqrs.org DDD/CQRS Google Group -
http://groups.google.com/group/dddcqrs Udi Dahan’s CQRS article “Clarified CQRS” –
http://www.udidahan.com/2009/12/09/clarified-cqrs/
Rinat Abdullin’s CQRS information – http://abdullin.com/cqrs
Distributed Podcast - http://distributedpodcast.com/