Upload
mitinpavel
View
1.881
Download
2
Embed Size (px)
DESCRIPTION
Presentation for a coffee'n'code meeting in Donetsk
Citation preview
Command Query Responsibility Segregation andEvent SourcingCQRS/ESMitin Pavel cnc.dn.ua 2012
Authors
Greg YoungUdi Dahan
http://www.domainlanguage.com/
Preface1. Probably you don't need CQRS/ES2. Do not consider CQRS to be a top-level
architectural pattern
Driving forces1. Collaboration2. Staleness
Query and command sides
http://www.gridshore.nl/2009/12/21/cqrs-made-easy-with-cqrs4j
Event sourcing● The single source of truth● Capture all changes to an application state
as a sequence of events● Metaphor -- a version control system
Event log facilities● Complete rebuild● Temporal query● Event replay
Event Store● Simple event store consists of 78 lines of C#● Snapshots as performance optimization
Persistence options● RDBMS● Aggregate-oriented database
Validation● Validation ● Business rules
Asynchronous interface● Validation results are available immediately● Business rule output are delayed in time
Capture user's intentTask-based UI
Code: commandhttps://github.com/gregoryyoung/m-r.git
public class DeactivateInventoryItem : Command { public readonly Guid InventoryItemId; public readonly int OriginalVersion;
public DeactivateInventoryItem(Guid inventoryItemId, int originalVersion) { InventoryItemId = inventoryItemId; OriginalVersion = originalVersion; }}
Code: eventpublic class InventoryItemDeactivated : Event { public readonly Guid Id;
public InventoryItemDeactivated(Guid id) { Id = id; }}
Code: controllerpublic class HomeController : Controller{ private FakeBus _bus; ...
public ActionResult Deactivate(Guid id, int version) { _bus.Send(new DeactivateInventoryItem(id, version)); return RedirectToAction("Index"); }
Code: command handlerpublic class InventoryCommandHandlers{ private readonly IRepository<InventoryItem> _repository; ...
public void Handle(DeactivateInventoryItem message) { // Construct item from stream of events var item = _repository.GetById(message.InventoryItemId); item.Deactivate(); _repository.Save(item, message.OriginalVersion); }
Code: write modelpublic class InventoryItem : AggregateRoot{ public void Deactivate() { if(!_activated) throw new InvalidOperationException("already deactivated"); ApplyChange(new InventoryItemDeactivated(_id)); }
private void Apply(InventoryItemDeactivated e) { _activated = false; }
Code: read modelpublic class InventoryListView : Handles<InventoryItemCreated>, Handles<InventoryItemRenamed>, Handles<InventoryItemDeactivated>{ ....
public void Handle(InventoryItemDeactivated message) { BullShitDatabase.list.RemoveAll(x => x.Id == message.Id); } }
Code: controllerpublic class HomeController : Controller{ private ReadModelFacade _readmodel; ...
public ActionResult Details(Guid id) { ViewData.Model = _readmodel.GetInventoryItemDetails(id); return View(); }
Polyglot programming● Javascript vs <you name it>● Static typing for the command side vs
dynamic typing for the query side● Core team vs outsourcers ;)
Top level architecture● Don't do It. Just don't● CQRS frameworks push you toward the anti-
pattern
Benefits of CQRS/ES● handling complexity● high-performance handling● integrating with third party systems● [ES] new reports from the historical data● [ES] behavioral analysis