CQRS in an hour or so 1 Who is jdn? • Me, aka John Nuechterlein • Blog: http://www.blogcoward.com • Operations Manager – Developer – Architect Raging Douchebag • eCom then Finance hopefully ecom again background • Ph.D. in Philosophy (University of Miami at the age of 25) – HI JEREMY!!!!!!! 2 Sources • Greg Young – http://codebetter.com/blogs/gregyoung/archive/2 009/08/13/command-query-separation.aspx • Udi Dahan – http://www.udidahan.com/2009/12/09/clarifiedcqrs/ • Mark Nijhof – http://elegantcode.com/2009/11/11/cqrs-la-gregyoung/ 3 CQRS • CQRS = “Command Query Responsibility Segregation” • Huh? • A design – pattern -architecture – Framework – Principle – Something • Makes stuff better • Huh? 4 CQS Defined • Bertrand Meyer (via Wikipedia) • “Command Query Separation” – “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.” 5 CQRS defined • Meyer: Separate command methods that change state from query methods that read state. • Greg Young: Separate command messages that change state from query messages that read state. • Can have significant architectural implications 6 Nihjof #1 7 Nihjof #2 8 Nihjof Categories • • • • 1 – Queries 2 – Commands 3 – Internal Events 4 – External Events 9 UDI #1 10 Queries • ‘Reporting’ – Misleading description (Greg’s fault), but makes some sense • Simple Query Layer – Simple views or sprocs or selects from denormalized tables • Simple DTOs, no mapping needed – Don’t go through the Domain Model, as it pollutes it – ViewModel per query perhaps – Why should the data come across 5 layers through 3 model transformations to populate a screen? (Udi) • ‘Traditional Reporting’ – Can (almost always will) have its own Model as well (and perhaps/probably its own data source) • Synchronous, no messaging needed • Eventual Consistency (more later) 11 Queries • No mapping code, don’t even bother getting a domain object at all, e.g.: • public class ModelDetailBrickDTOMapper : IMapper<Model, ModelDetailBrickDTO> • { • public ModelDetailBrickDTO Map(Model m) • { • return new ModelDetailBrickDTO(m.ID, m.Name, m.Description, m.Details, m.ShippingMessage, m.GetPrice("Current"), m.GetPrice("MSRP"), m.Sizes, m.Images, DisplayProductBrick.GetRelatedDisplayProductBricksByModel(m)) ; • } • } 12 Queries • Data store – Cache it (it’s already stale) – Why not on web-tier? – Why relational? • Horizontal scalability – If you cache, add a new server to handle it 13 Commands • Commands capture intent, DTOs don’t – CustomerDTO vs CustomerChangedAddressCommand • • • • Part of the ‘Ubiquitous’ Language Handler per command Can be validated outside of domain entities This is why no getters/setters on domain entities, their state is updated by processing commands according to the rules of the business • This is why domain entities are never invalid, commands that would produce invalid state are rejected 14 Commands • Separate Data Modification – Make preferred – Change address – Delinquent payment event example • Comes in 1 ms after make preferred event • What to do? – A generic DTO could do these things, of course, but after the fact, how do you know what actually happened? • UI Implications – Excel-like screens don’t work – Commands require specific intent 15 Commands • Commands can be queued – Split into separate queues • Scale where needed • Commands don’t have to be handled by the domain 16 Internal Events • Triggered by commands • Can be persisted – Could be RDBMS, ODBMS, Document DB, etc. – Event sourcing (big topic, punting) • Can be replayed – Production support benefit • Snapshots can also be created & persisted – Don’t delete original events • Domain can accept command or reject it – Raise event either way 17 Internal Events • Write-only – “Accountants don’t use erasers” • Compensating Actions/Events – Instead of rolling back a transaction, you compensate for some failure • Automatic audit log – You have all the events that happened • No more ‘impedence mismatch’ – You are persisting events, not rows • Data mining – Like I said, you have all the events that happened 18 External Events • Publishing – Typically, message bus – Could use views or ETL to process in a ‘simpler’ architecture • Data stores can subscribe • Only process when a read request comes in (GY) 19 External Events • Publishing external events and persisting internal events done in a transaction • Eventual Consistency – Latency is almost always okay – Question is, how much? – Availability trumps correctness – Acting on incomplete data is normal • Event handler per view model, perhaps 20 Why not CQRS? • • • • • It’s new, it’s different, I’m stupid Multiple data stores Operational Complexity Losing ACID/Transactions is scary Lots of Commands and Events and Handlers and Lions and Tigers and Bears oh my! to Code 21 Questions? 22