Most of us will be familiar with the standard 3- or 4-layer architecture you often see in larger enterprise systems. Some are already practicing Domain Driven Design and work together with the business to clarify the domain concepts. Perhaps you’ve noticed that is difficult to get the intention of the 'verbs' from that domain into this standard architecture. If performance is an important requirement as well, then you might have discovered that an Object-Relational Mapper and a relational database are not always the best solution.
One of the main reasons for this is the fact that the interests of a consistent domain that takes into account the many business rules, and those of data reporting and presentation are conflicting. That’s why Betrand Meyer introduced the Command Query Separation principle.
An architecture based on this principle combined with the Event Sourcing concept provides the ideal architecture for building high-performance systems designed using DDD. Well-known bloggers like Udi Dahan and Greg Young have already spent quite a lot of of posts on this, and this year’s Developer Days had some coverage as well.
But how do you build such a system with the. NET framework? Is it really as complex as some claim, or is just different work?
CQRS and Event Sourcing, An Alternative Architecture for DDD
1. CQRS & Event Sourcing An alternative architecture for DDD Dennis Doomen
2. The default architecture A better architecture The alternative architecture Advanced topics Contents
3. The Default Architecture Easy to build Accepted by management Well known Lots of resources Lots of frameworks Silverlight Application No concurrency Scalability limited No domain verbs Granularity DTOs Unneccesary DTO conversions Conflicting demands Proxy DTOs Services Domain Services Domain Model Repositories Unit of Work Service Agents RelationalDatabase Backoffice Systems
4. CQRS Silverlight Application Commands are verbs No DTO conversion Easy to build disconnected clients Query Store = No SQL Very scalable Service Agent Queries Business Actions DTOs Commands Command Service Query Service Command Handlers Domain Services Domain Model Data Access Layer Repositories UoW Service Agents Difficult to sync database No concurrency Requires a task-based UI Complexity RelationalDatabase Query Store Backoffice Systems Changes Query Store
5. Task-based UIs a.k.a. Inductive UIs answer: What am I supposed to do now? Where do I go from here to accomplish my task? Task-based UIs
6. Focus screens on single task Make the task’s intention clear Offer links to secondary tasks Provide screens for starting tasks Make the next step obvious From Microsoft Inductive User Interface Guidelines Guidelines for Task-based UIs
7. Are valid or not, regardless of context Named in Ubiquitous Language State intent Can be asynchronous... ...but beware of eventual consistency Rejection via exception or fault event Commands
8. One table per UI view Exposed through SOA-style web services WCF data services WCF RIA Services Can be anything Relational Database No SQL database XML files Query Store
9. CQRS & Event Sourcing Silverlight Application Great performance Conflict Merging Historical Tracking Trival Synchronization Easy Integration Independent Query Store Queries Service Agent Business Actions Commands DTOs Command Service Command Handlers Domain Services Domain Model Events Query Service Denormalizer Events Event Handlers Lots of new concepts Not so acceptable Few resources No consensus yet More complexity Aggregate boundaries important Data Access Layer UoW Event Bus Domain Repository Service Agents Query Store Event Store Query Store Backoffice Systems Events
10. Represent state changes in aggregate root Named in passed tense Using Ubiquitous Language Entire aggregate is stored in serialized format Events never change Snapshots to improve performance Events
11. Have no relationships (!) Communicate through events Entities do not expose setters (!) Apply events to themselves State exposed as mementos Aggregate Roots
13. Event Schema Versioning - Adds missing properties - Renames renamed properties - Converts values Post Converter Property Bag Converter Post Converter Post Converter id = 123 SQL Server Domain Repository Event Store Property Bag Get(id = 123) Event id = 123
14. Event Store != relational database...so no unique constraints Workarounds Check uniqueness through query side Add generic unique column to event store Introduce a parent that enforces uniqueness Unique Constraints
15. The CQRS Kitchen Views (XAML + C#) View Models Application Services Unity Service Agent Commands DTOs Command Service Command Handlers WCF Domain Services Mementos Domain Model Unity Enterprise Library 5 NCQRS++ NSerivceBus Events Event Handlers Event Bus Domain Repository Events UoW Event Store Query Service Denormalizers WCF Data Services Thin Data Access Layer Entity Framework 4 SQL Server Entity Framework 4 SQL Server
16. NCQRS The CQRS framework for .NET http://ncqrs.codeplex.com/ Very promising Great Documentation Quality code Uses Code Contracts Very active team I’m considering joining (Still) difficult to get started Not proven yet Not complete yet Feels a bit too complex Not everything is pluggable Misses a coding standard
17. In summary Great for performance Very scalable Supports historical auditing Supports high concurrency Easy to integrate with other systems Very testable with TDD/DDD Aligns great with Ubiquitous Language Doesn’t require expensive RDBMS Lots of new concepts Lots of choices to make Not yet accepted by management Limited documentation No consensus yet More complexity Aggregate design is important I haven’t found all issues yet
18. Background InformationGreg Young, Mark Nijhof, Udi Dahan, Jonathan Oliver Example Code, FrameworksThe CQRS Kitchen, NCQRS Interaction Design / Task-Based UIsThe Inmates Are Running The Asylum, Alan CooperMicrosoft Inductive User Interface Guidelines Links
DisadvantagesNo concurrency; conflicting service requests are simply rejectedStaleness ignored;Scalability limited; No domain verbs; domain model does contain concepts from the domain model, just not the business actionsGranularity DTOs; What operations to expose in your WCF service? What relations to include and when? What domain entities to flatten.Unneccesary DTO conversions; Conversions from/to domain model entities, traversing of relations, eager fatchingConflicting demands; query demands denormalized schema, commands require normalized integer schema
DisadvantagesNo concurrency; conflicting service requests are simply rejectedStaleness ignored;Scalability limited; No domain verbs; domain model does contain concepts from the domain model, just not the business actionsGranularity DTOs; What operations to expose in your WCF service? What relations to include and when? What domain entities to flatten.Unneccesary DTO conversions; Conversions from/to domain model entities, traversing of relations, eager fatchingConflicting demands; query demands denormalized schema, commands require normalized integer schema
Commands validate itself without using any context, thus is valid or not instead of sometimes.Commands are named in the Ubiquitous LanguageCommands can be send asynchronously, and thus can be resistent to database unavailabilityMogelijk meerdere commands met dezeflde state change: CorrectCustomerAddress, MoveCustomerCommand interfaces: in-memory, WCF, WCF RIA Services, NServiceBus, etc
DisadvantagesNo concurrency; conflicting service requests are simply rejectedStaleness ignored;Scalability limited; No domain verbs; domain model does contain concepts from the domain model, just not the business actionsGranularity DTOs; What operations to expose in your WCF service? What relations to include and when? What domain entities to flatten.Unneccesary DTO conversions; Conversions from/to domain model entities, traversing of relations, eager fatchingConflicting demands; query demands denormalized schema, commands require normalized integer schema
DisadvantagesNo concurrency; conflicting service requests are simply rejectedStaleness ignored;Scalability limited; No domain verbs; domain model does contain concepts from the domain model, just not the business actionsGranularity DTOs; What operations to expose in your WCF service? What relations to include and when? What domain entities to flatten.Unneccesary DTO conversions; Conversions from/to domain model entities, traversing of relations, eager fatchingConflicting demands; query demands denormalized schema, commands require normalized integer schema