command query responsibility segregation and event sourcing

Post on 07-Dec-2014

1.881 Views

Category:

Technology

2 Downloads

Preview:

Click to see full reader

DESCRIPTION

Presentation for a coffee'n'code meeting in Donetsk

TRANSCRIPT

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

top related