SlideShare une entreprise Scribd logo
1  sur  42
DDD South West 2An Introduction to CQRS approaches to system architecture @NeilRobbins neil@computer.org
Aims An overview of CQRS UI Command Handling View Handling How to write an Event Sourced DDD system The command handling bit
But first some code To Visual Studio!
What’s wrong with this?  public class Event     {         public string Name { get; set; }         public int Venue { get; set; }         public DateTime Date { get; set; }         public IEnumerable<Session> Sessions { get; set; }     }     public class Session     {         public PresentationPresentation { get; set; }         public string Location { get; set; }         public DateTime Time { get; set; }     }
But what about Queries? They’re just queries They support the UI which should provide a Decision Support System
Intentful UI Shopping Cart Service Command Command Ratings Service Command Command Product Images Service Command Command Command Buying Choices Service Offers Service Bought Together Service
Intentful UI Captures Intent Aligns with commands Uses the query infrastructure For display For decision support Commands should succeed Will contain logic, is typically rich
Some Slides Big picture & background stuff!
Façadelient Bus Commands Eventually Consistent Queries Handler
Subscriber Subscriber Publisher Subscribers Subscriber
ID : 123 Name : The Art of War Author: Sun Tzu ISBN: 1234ABCD5678 Event: BookIsbnChanged NewValue: 4321DCBA8765
…there are times when we don't just want to see where we are, we also want to know how we got there http://martinfowler.com/eaaDev/EventSourcing.html
Time to See Some Code You didn’t think I’d make you watch me type did you?
Coding for EventSourcing namespaceProgNetDemo { public classCatalogItem     {     } }
A Command Method namespaceProgNetDemo { public classCatalogItem     {  public void Retire()       	{         	}     } }
Some State To Change namespaceProgNetDemo { public classCatalogItem     { privatebool _retired;  public void Retire()       	{         	}     } }
Guard the Mutation namespaceProgNetDemo { public classCatalogItem     { privatebool _retired;  public void Retire()       	{ if (!_retired) thrownewInvalidOperationException();         	}     } }
Make the State Mutation A Domain Event namespaceProgNetDemo { public classCatalogItem     { privatebool _retired;  public void Retire()       	{ if (!_retired) thrownewInvalidOperationException(); ApplyEvent(new RetiredEvent(_id));         	}     } }
Need an Identifier for the Aggregate public classCatalogItem { privatebool _retired; privateGuid_id;  public void Retire() 	{ if (!_retired) thrownewInvalidOperationException(); ApplyEvent(new RetiredEvent(_id));     	} }
Create the Event publicclassRetiredEvent { privatereadonlyGuid _id; publicRetiredEvent(Guid id)     { 		_id = id; 	} }
Need to be Able to Apply the Event public classCatalogItem { privatebool _retired; privateGuid_id;  public void Retire() 	{ if (!_retired) thrownewInvalidOperationException(); ApplyEvent(new RetiredEvent(_id));     	} }
Create a Base Class public classAggregateRoot  { protected voidApplyEvent(Event @event) 	{ 	} } We’ll need to handle more than just the one type of event!
Create the Event Type public classEvent { }
Have our RetiredEvent Inherit From the Base Type publicclassRetiredEvent : Event { privatereadonlyGuid _id; publicRetiredEvent(Guid id)     { 		_id = id; 	} }
Still Need to Mutate the State public classCatalogItem : AggregateRoot { privatebool _retired; privateGuid_id;  public void Retire() 	{ if (!_retired) thrownewInvalidOperationException(); ApplyEvent(new RetiredEvent(_id));     	} }
Create a Method to Handle the State Change From the Event public classCatalogItem : AggregateRoot { privatebool _retired; privateGuid_id;  public void Retire() 	{ if (!_retired) thrownewInvalidOperationException(); ApplyEvent(new RetiredEvent(_id));     	} private voidApplyRetiredEvent(RetiredEvent @event) 	{ 		_retired = true; 	} }
Done!? public classCatalogItem : AggregateRoot { privatebool _retired; privateGuid_id;  public void Retire() 	{ if (!_retired) thrownewInvalidOperationException(); ApplyEvent(new RetiredEvent(_id));     	} private voidApplyRetiredEvent(RetiredEvent @event) 	{ 		_retired = true; 	} }
Need to Connect the Event with the Handler public classCatalogItem : AggregateRoot { privatebool _retired; privateGuid_id; publicCatalogItem() 	{ RegisterHandler<RetiredEvent>(ApplyRetiredEvent); 	}  public void Retire() 	{ if (!_retired) thrownewInvalidOperationException(); ApplyEvent(new RetiredEvent(_id));     	} private voidApplyRetiredEvent(RetiredEvent @event) 	{ 		_retired = true; 	} }
Allow Handlers to be Registered public classAggregateRoot  { protected voidRegisterHandler<TEvent>(AppliesEvent<TEvent> handler) whereTEvent : Event 	{ 	} protected voidApplyEvent(Event @event) 	{ 	} }
Create the Delegate Signature public delegate voidAppliesEvent<TEvent>(TEvent @event) where TEvent : Event; public classAggregateRoot  { protected voidRegisterHandler<TEvent>(AppliesEvent<TEvent> handler) whereTEvent : Event 	{ 	} protected voidApplyEvent(Event @event) 	{ 	} }
Need to Maintain the Registry public delegate voidAppliesEvent<TEvent>(TEvent @event) where TEvent : Event; public classAggregateRoot  { private readonlyIDictionary<Type, Action<Event>> _handlerRegistry; protected voidRegisterHandler<TEvent>(AppliesEvent<TEvent> handler) whereTEvent : Event 	{ var castHandler =  		        DelegateAdjuster.CastArgument<Event, TEvent>(e => handler(e)); 	} protected voidApplyEvent(Event @event) 	{ 	} }
Delegate Adjuster:From Greg’s Blog public class DelegateAdjuster {     public static Action<TBase> CastArgument<TBase, TDerived>(Expression<Action<TDerived>> source) whereTDerived : TBase {         if (typeof(TDerived) ==typeof(TBase)) {             return (Action<TBase>)((Delegate)source.Compile()); } ParameterExpressionsourceParameter = Expression.Parameter(typeof(TBase),"source"); varresult = Expression.Lambda<Action<TBase>>( Expression.Invoke(                 source, Expression.Convert(sourceParameter, typeof(TDerived))), sourceParameter);         return result.Compile(); } }
Need to Maintain the Registry public delegate voidAppliesEvent<TEvent>(TEvent @event) where TEvent : Event; public classAggregateRoot  { private readonlyIDictionary<Type, Action<Event>> _handlerRegistry; protected voidRegisterHandler<TEvent>(AppliesEvent<TEvent> handler) whereTEvent : Event 	{ var castHandler =  		        DelegateAdjuster.CastArgument<Event, TEvent>(e => handler(e)); 		 _handlerRegistry.Add(typeof(TEvent), castHandler); 	} protected voidApplyEvent(Event @event) 	{ 	} }
Need to Apply the Event Still public delegate voidAppliesEvent<TEvent>(TEvent @event) where TEvent : Event; public classAggregateRoot  { private readonlyIDictionary<Type, Action<Event>> _handlerRegistry; protected voidRegisterHandler<TEvent>(AppliesEvent<TEvent> handler) whereTEvent : Event 	{ var castHandler =  		        DelegateAdjuster.CastArgument<Event, TEvent>(e => handler(e)); 		 _handlerRegistry.Add(typeof(TEvent), castHandler); 	} protected voidApplyEvent(Event @event) 	{ Action<Event> handler; if (!_handlerRegistry.TryGetValue(@event.GetType(), out handler)) 		{ throw newInvalidOperationException(); 		} 		handler(@event); 	} }
Need to Track Applied Events public delegate voidAppliesEvent<TEvent>(TEvent @event) where TEvent : Event; public classAggregateRoot  { private readonlyIDictionary<Type, Action<Event>> _handlerRegistry; private readonlyICollection<Event> _events; protected voidRegisterHandler<TEvent>(AppliesEvent<TEvent> handler) whereTEvent : Event 	{ var castHandler =  		        DelegateAdjuster.CastArgument<Event, TEvent>(e => handler(e)); 		 _handlerRegistry.Add(typeof(TEvent), castHandler); 	} protected voidApplyEvent(Event @event) 	{ Action<Event> handler; if (!_handlerRegistry.TryGetValue(@event.GetType(), out handler)) 		{ throw newInvalidOperationException(); 		} 		handler(@event); 		_events.Add(@event); 	} }
All done now??? public classCatalogItem : AggregateRoot { privatebool _retired; privateGuid_id; publicCatalogItem() 	{ RegisterHandler<RetiredEvent>(ApplyRetiredEvent); 	}  public void Retire() 	{ if (!_retired) thrownewInvalidOperationException(); ApplyEvent(new RetiredEvent(_id));     	} private voidApplyRetiredEvent(RetiredEvent @event) 	{ 		_retired = true; 	} } Could use a convention & just make the AggregateRoot declare which events it produces
Not Quite Need to Expose the events for persistence & publishing Put a GetChanges() method on the AggregateRoot base class Need to be able to rebuild the Aggregate from history Put a LoadFromHistory(IEnumerable<Event> events) method on the AggregateRoot base class Reapply the events Don’t track them as changes – overload apply event protected voidApplyEvent(Event @event, booltrackAsChange) if (add) _events.Add(@event); Possibly memento pattern for snapshoting See Mark Nijhof’s blog & sample code on GitHub
Back to the Whiteboard! Some more on Query Stores
Some Other Benefits of Event Sourcing Already We can build new stores for new services, we have the full set of available information ready We can rebuild stores for existing services We use the same mechanism for our Query Stores as we use for any other service in the Enterprise More Granular Service Boundaries More Explicit Boundaries We aren’t just restricted to storing the Events Can send Emails based on them Can perform Complex Event Processing … The worlds your Oyster, you have the RAW MATERIAL
Some Other Benefits of Event Sourcing Also A Very Provable Audit Log Very Simple Horizontal Scaling More Granular Service Boundaries More Explicit Boundaries Can Replay Events in Debugging Scenarios Suits Behaviour Based Testing & Outside-In Development
NO SILVER BULLETS The coding is the EASY BIT Don’t need a grand framework The thinking & conversations is the HARD BIT
Referenced Material/Links Greg Youngs: Course – http://bit.ly/gregscourse Blog – http://bit.ly/gregyoungsblog UdiDahans: Course – http://bit.ly/udiscourse Blog – http://bit.ly/udisblog Mark Nijhof’s sample code http://github.com/MarkNijhof/Fohjin

Contenu connexe

Tendances

Stay with React.js in 2020
Stay with React.js in 2020Stay with React.js in 2020
Stay with React.js in 2020Jerry Liao
 
A (very) opinionated guide to MSBuild and Project Files
A (very) opinionated guide to MSBuild and Project FilesA (very) opinionated guide to MSBuild and Project Files
A (very) opinionated guide to MSBuild and Project FilesDavid Wengier
 
A GWT Application with MVP Pattern Deploying to CloudFoundry using Spring Roo
A GWT Application with MVP Pattern Deploying to CloudFoundry using  Spring Roo A GWT Application with MVP Pattern Deploying to CloudFoundry using  Spring Roo
A GWT Application with MVP Pattern Deploying to CloudFoundry using Spring Roo Ali Parmaksiz
 
Automated%20testing%20with%20Espresso2.x
Automated%20testing%20with%20Espresso2.xAutomated%20testing%20with%20Espresso2.x
Automated%20testing%20with%20Espresso2.xTatsuya Maki
 
CDI do básico ao avançado
CDI do básico ao avançadoCDI do básico ao avançado
CDI do básico ao avançadoAlberto Souza
 
Rapid development tools for java ee 8 [tut2998]
Rapid development tools for java ee 8 [tut2998]Rapid development tools for java ee 8 [tut2998]
Rapid development tools for java ee 8 [tut2998]Payara
 
Migrating from Flux to Redux. Why and how.
Migrating from Flux to Redux. Why and how.Migrating from Flux to Redux. Why and how.
Migrating from Flux to Redux. Why and how.Astrails
 
code for quiz in my sql
code for quiz  in my sql code for quiz  in my sql
code for quiz in my sql JOYITAKUNDU1
 
Oleksandr Valetskyy - DI vs. IoC
Oleksandr Valetskyy - DI vs. IoCOleksandr Valetskyy - DI vs. IoC
Oleksandr Valetskyy - DI vs. IoCOleksandr Valetskyy
 
Intro to React | DreamLab Academy
Intro to React | DreamLab AcademyIntro to React | DreamLab Academy
Intro to React | DreamLab AcademyDreamLab
 
Protocol-Oriented Networking
Protocol-Oriented NetworkingProtocol-Oriented Networking
Protocol-Oriented NetworkingMostafa Amer
 
My way to clean android - Android day salamanca edition
My way to clean android - Android day salamanca editionMy way to clean android - Android day salamanca edition
My way to clean android - Android day salamanca editionChristian Panadero
 

Tendances (20)

Stay with React.js in 2020
Stay with React.js in 2020Stay with React.js in 2020
Stay with React.js in 2020
 
A (very) opinionated guide to MSBuild and Project Files
A (very) opinionated guide to MSBuild and Project FilesA (very) opinionated guide to MSBuild and Project Files
A (very) opinionated guide to MSBuild and Project Files
 
A GWT Application with MVP Pattern Deploying to CloudFoundry using Spring Roo
A GWT Application with MVP Pattern Deploying to CloudFoundry using  Spring Roo A GWT Application with MVP Pattern Deploying to CloudFoundry using  Spring Roo
A GWT Application with MVP Pattern Deploying to CloudFoundry using Spring Roo
 
Automated%20testing%20with%20Espresso2.x
Automated%20testing%20with%20Espresso2.xAutomated%20testing%20with%20Espresso2.x
Automated%20testing%20with%20Espresso2.x
 
Introduction to android
Introduction to androidIntroduction to android
Introduction to android
 
CDI do básico ao avançado
CDI do básico ao avançadoCDI do básico ao avançado
CDI do básico ao avançado
 
Rapid development tools for java ee 8 [tut2998]
Rapid development tools for java ee 8 [tut2998]Rapid development tools for java ee 8 [tut2998]
Rapid development tools for java ee 8 [tut2998]
 
Migrating from Flux to Redux. Why and how.
Migrating from Flux to Redux. Why and how.Migrating from Flux to Redux. Why and how.
Migrating from Flux to Redux. Why and how.
 
code for quiz in my sql
code for quiz  in my sql code for quiz  in my sql
code for quiz in my sql
 
Easy Button
Easy ButtonEasy Button
Easy Button
 
React lecture
React lectureReact lecture
React lecture
 
Nativescript angular
Nativescript angularNativescript angular
Nativescript angular
 
Android TDD
Android TDDAndroid TDD
Android TDD
 
Rxjs marble-testing
Rxjs marble-testingRxjs marble-testing
Rxjs marble-testing
 
Oleksandr Valetskyy - DI vs. IoC
Oleksandr Valetskyy - DI vs. IoCOleksandr Valetskyy - DI vs. IoC
Oleksandr Valetskyy - DI vs. IoC
 
Backbone Basics with Examples
Backbone Basics with ExamplesBackbone Basics with Examples
Backbone Basics with Examples
 
Maze
MazeMaze
Maze
 
Intro to React | DreamLab Academy
Intro to React | DreamLab AcademyIntro to React | DreamLab Academy
Intro to React | DreamLab Academy
 
Protocol-Oriented Networking
Protocol-Oriented NetworkingProtocol-Oriented Networking
Protocol-Oriented Networking
 
My way to clean android - Android day salamanca edition
My way to clean android - Android day salamanca editionMy way to clean android - Android day salamanca edition
My way to clean android - Android day salamanca edition
 

En vedette

Event-driven architecture
Event-driven architectureEvent-driven architecture
Event-driven architectureAndrew Easter
 
Eventsourcing with PHP and MongoDB
Eventsourcing with PHP and MongoDBEventsourcing with PHP and MongoDB
Eventsourcing with PHP and MongoDBJacopo Nardiello
 
CQRS & Event Sourcing in the wild (ScotlandPHP 2016)
CQRS & Event Sourcing in the wild (ScotlandPHP 2016)CQRS & Event Sourcing in the wild (ScotlandPHP 2016)
CQRS & Event Sourcing in the wild (ScotlandPHP 2016)Michiel Rook
 
Event sourcing
Event sourcingEvent sourcing
Event sourcingRich Lee
 
From ActiveRecord to EventSourcing
From ActiveRecord to EventSourcingFrom ActiveRecord to EventSourcing
From ActiveRecord to EventSourcingEmanuele DelBono
 
TYPO3 Event Sourcing
TYPO3 Event SourcingTYPO3 Event Sourcing
TYPO3 Event SourcingOliver Hader
 
DDD Framework for Java: JdonFramework
DDD Framework for Java: JdonFrameworkDDD Framework for Java: JdonFramework
DDD Framework for Java: JdonFrameworkbanq jdon
 
The 6 Rules for Modernizing Your Legacy Java Monolith with Microservices
The 6 Rules for Modernizing Your Legacy Java Monolith with MicroservicesThe 6 Rules for Modernizing Your Legacy Java Monolith with Microservices
The 6 Rules for Modernizing Your Legacy Java Monolith with MicroservicesLightbend
 

En vedette (12)

Event your life with Kafka
Event your life with KafkaEvent your life with Kafka
Event your life with Kafka
 
Event-driven architecture
Event-driven architectureEvent-driven architecture
Event-driven architecture
 
Eventsourcing with PHP and MongoDB
Eventsourcing with PHP and MongoDBEventsourcing with PHP and MongoDB
Eventsourcing with PHP and MongoDB
 
Event Sourcing with php
Event Sourcing with phpEvent Sourcing with php
Event Sourcing with php
 
EventSourcing applied
EventSourcing appliedEventSourcing applied
EventSourcing applied
 
Event-sourcing avancé avec Scala
Event-sourcing avancé avec ScalaEvent-sourcing avancé avec Scala
Event-sourcing avancé avec Scala
 
CQRS & Event Sourcing in the wild (ScotlandPHP 2016)
CQRS & Event Sourcing in the wild (ScotlandPHP 2016)CQRS & Event Sourcing in the wild (ScotlandPHP 2016)
CQRS & Event Sourcing in the wild (ScotlandPHP 2016)
 
Event sourcing
Event sourcingEvent sourcing
Event sourcing
 
From ActiveRecord to EventSourcing
From ActiveRecord to EventSourcingFrom ActiveRecord to EventSourcing
From ActiveRecord to EventSourcing
 
TYPO3 Event Sourcing
TYPO3 Event SourcingTYPO3 Event Sourcing
TYPO3 Event Sourcing
 
DDD Framework for Java: JdonFramework
DDD Framework for Java: JdonFrameworkDDD Framework for Java: JdonFramework
DDD Framework for Java: JdonFramework
 
The 6 Rules for Modernizing Your Legacy Java Monolith with Microservices
The 6 Rules for Modernizing Your Legacy Java Monolith with MicroservicesThe 6 Rules for Modernizing Your Legacy Java Monolith with Microservices
The 6 Rules for Modernizing Your Legacy Java Monolith with Microservices
 

Similaire à An intro to cqrs

Durable functions 2.0 (2019-10-10)
Durable functions 2.0 (2019-10-10)Durable functions 2.0 (2019-10-10)
Durable functions 2.0 (2019-10-10)Paco de la Cruz
 
Working effectively with legacy code
Working effectively with legacy codeWorking effectively with legacy code
Working effectively with legacy codeShriKant Vashishtha
 
CDI e as ideias pro futuro do VRaptor
CDI e as ideias pro futuro do VRaptorCDI e as ideias pro futuro do VRaptor
CDI e as ideias pro futuro do VRaptorCaelum
 
Improving android experience for both users and developers
Improving android experience for both users and developersImproving android experience for both users and developers
Improving android experience for both users and developersPavel Lahoda
 
Droidcon2013 android experience lahoda
Droidcon2013 android experience lahodaDroidcon2013 android experience lahoda
Droidcon2013 android experience lahodaDroidcon Berlin
 
Overview of Android Infrastructure
Overview of Android InfrastructureOverview of Android Infrastructure
Overview of Android InfrastructureAlexey Buzdin
 
Overview of Android Infrastructure
Overview of Android InfrastructureOverview of Android Infrastructure
Overview of Android InfrastructureC.T.Co
 
Getting the Most Out of jQuery Widgets
Getting the Most Out of jQuery WidgetsGetting the Most Out of jQuery Widgets
Getting the Most Out of jQuery Widgetsvelveeta_512
 
Android Best Practices
Android Best PracticesAndroid Best Practices
Android Best PracticesYekmer Simsek
 
重構—改善既有程式的設計(chapter 8)part 1
重構—改善既有程式的設計(chapter 8)part 1重構—改善既有程式的設計(chapter 8)part 1
重構—改善既有程式的設計(chapter 8)part 1Chris Huang
 
Azure Durable Functions (2019-04-27)
Azure Durable Functions (2019-04-27)Azure Durable Functions (2019-04-27)
Azure Durable Functions (2019-04-27)Paco de la Cruz
 
VISUALIZAR REGISTROS EN UN JTABLE
VISUALIZAR REGISTROS EN UN JTABLEVISUALIZAR REGISTROS EN UN JTABLE
VISUALIZAR REGISTROS EN UN JTABLEDarwin Durand
 
DWR, Hibernate and Dojo.E - A Tutorial
DWR, Hibernate and Dojo.E - A TutorialDWR, Hibernate and Dojo.E - A Tutorial
DWR, Hibernate and Dojo.E - A Tutorialjbarciauskas
 
Ten useful JavaScript tips & best practices
Ten useful JavaScript tips & best practicesTen useful JavaScript tips & best practices
Ten useful JavaScript tips & best practicesAnkit Rastogi
 
Thomas braun dependency-injection_with_robo_guice-presentation-final
Thomas braun dependency-injection_with_robo_guice-presentation-finalThomas braun dependency-injection_with_robo_guice-presentation-final
Thomas braun dependency-injection_with_robo_guice-presentation-finalDroidcon Berlin
 

Similaire à An intro to cqrs (20)

Durable functions 2.0 (2019-10-10)
Durable functions 2.0 (2019-10-10)Durable functions 2.0 (2019-10-10)
Durable functions 2.0 (2019-10-10)
 
Working effectively with legacy code
Working effectively with legacy codeWorking effectively with legacy code
Working effectively with legacy code
 
Clean coding-practices
Clean coding-practicesClean coding-practices
Clean coding-practices
 
CDI e as ideias pro futuro do VRaptor
CDI e as ideias pro futuro do VRaptorCDI e as ideias pro futuro do VRaptor
CDI e as ideias pro futuro do VRaptor
 
Why realm?
Why realm?Why realm?
Why realm?
 
Improving android experience for both users and developers
Improving android experience for both users and developersImproving android experience for both users and developers
Improving android experience for both users and developers
 
Droidcon2013 android experience lahoda
Droidcon2013 android experience lahodaDroidcon2013 android experience lahoda
Droidcon2013 android experience lahoda
 
Overview of Android Infrastructure
Overview of Android InfrastructureOverview of Android Infrastructure
Overview of Android Infrastructure
 
Overview of Android Infrastructure
Overview of Android InfrastructureOverview of Android Infrastructure
Overview of Android Infrastructure
 
Getting the Most Out of jQuery Widgets
Getting the Most Out of jQuery WidgetsGetting the Most Out of jQuery Widgets
Getting the Most Out of jQuery Widgets
 
Android Best Practices
Android Best PracticesAndroid Best Practices
Android Best Practices
 
重構—改善既有程式的設計(chapter 8)part 1
重構—改善既有程式的設計(chapter 8)part 1重構—改善既有程式的設計(chapter 8)part 1
重構—改善既有程式的設計(chapter 8)part 1
 
Azure Durable Functions (2019-04-27)
Azure Durable Functions (2019-04-27)Azure Durable Functions (2019-04-27)
Azure Durable Functions (2019-04-27)
 
VISUALIZAR REGISTROS EN UN JTABLE
VISUALIZAR REGISTROS EN UN JTABLEVISUALIZAR REGISTROS EN UN JTABLE
VISUALIZAR REGISTROS EN UN JTABLE
 
Android workshop
Android workshopAndroid workshop
Android workshop
 
DWR, Hibernate and Dojo.E - A Tutorial
DWR, Hibernate and Dojo.E - A TutorialDWR, Hibernate and Dojo.E - A Tutorial
DWR, Hibernate and Dojo.E - A Tutorial
 
Ten useful JavaScript tips & best practices
Ten useful JavaScript tips & best practicesTen useful JavaScript tips & best practices
Ten useful JavaScript tips & best practices
 
Thomas braun dependency-injection_with_robo_guice-presentation-final
Thomas braun dependency-injection_with_robo_guice-presentation-finalThomas braun dependency-injection_with_robo_guice-presentation-final
Thomas braun dependency-injection_with_robo_guice-presentation-final
 
Clean Javascript
Clean JavascriptClean Javascript
Clean Javascript
 
Jersey Guice AOP
Jersey Guice AOPJersey Guice AOP
Jersey Guice AOP
 

Dernier

Mysore Call Girls 8617370543 WhatsApp Number 24x7 Best Services
Mysore Call Girls 8617370543 WhatsApp Number 24x7 Best ServicesMysore Call Girls 8617370543 WhatsApp Number 24x7 Best Services
Mysore Call Girls 8617370543 WhatsApp Number 24x7 Best ServicesDipal Arora
 
Katrina Personal Brand Project and portfolio 1
Katrina Personal Brand Project and portfolio 1Katrina Personal Brand Project and portfolio 1
Katrina Personal Brand Project and portfolio 1kcpayne
 
Call Girls Zirakpur👧 Book Now📱7837612180 📞👉Call Girl Service In Zirakpur No A...
Call Girls Zirakpur👧 Book Now📱7837612180 📞👉Call Girl Service In Zirakpur No A...Call Girls Zirakpur👧 Book Now📱7837612180 📞👉Call Girl Service In Zirakpur No A...
Call Girls Zirakpur👧 Book Now📱7837612180 📞👉Call Girl Service In Zirakpur No A...Sheetaleventcompany
 
Call Girls Electronic City Just Call 👗 7737669865 👗 Top Class Call Girl Servi...
Call Girls Electronic City Just Call 👗 7737669865 👗 Top Class Call Girl Servi...Call Girls Electronic City Just Call 👗 7737669865 👗 Top Class Call Girl Servi...
Call Girls Electronic City Just Call 👗 7737669865 👗 Top Class Call Girl Servi...amitlee9823
 
Call Girls Kengeri Satellite Town Just Call 👗 7737669865 👗 Top Class Call Gir...
Call Girls Kengeri Satellite Town Just Call 👗 7737669865 👗 Top Class Call Gir...Call Girls Kengeri Satellite Town Just Call 👗 7737669865 👗 Top Class Call Gir...
Call Girls Kengeri Satellite Town Just Call 👗 7737669865 👗 Top Class Call Gir...amitlee9823
 
Quick Doctor In Kuwait +2773`7758`557 Kuwait Doha Qatar Dubai Abu Dhabi Sharj...
Quick Doctor In Kuwait +2773`7758`557 Kuwait Doha Qatar Dubai Abu Dhabi Sharj...Quick Doctor In Kuwait +2773`7758`557 Kuwait Doha Qatar Dubai Abu Dhabi Sharj...
Quick Doctor In Kuwait +2773`7758`557 Kuwait Doha Qatar Dubai Abu Dhabi Sharj...daisycvs
 
👉Chandigarh Call Girls 👉9878799926👉Just Call👉Chandigarh Call Girl In Chandiga...
👉Chandigarh Call Girls 👉9878799926👉Just Call👉Chandigarh Call Girl In Chandiga...👉Chandigarh Call Girls 👉9878799926👉Just Call👉Chandigarh Call Girl In Chandiga...
👉Chandigarh Call Girls 👉9878799926👉Just Call👉Chandigarh Call Girl In Chandiga...rajveerescorts2022
 
Call Girls Ludhiana Just Call 98765-12871 Top Class Call Girl Service Available
Call Girls Ludhiana Just Call 98765-12871 Top Class Call Girl Service AvailableCall Girls Ludhiana Just Call 98765-12871 Top Class Call Girl Service Available
Call Girls Ludhiana Just Call 98765-12871 Top Class Call Girl Service AvailableSeo
 
Dr. Admir Softic_ presentation_Green Club_ENG.pdf
Dr. Admir Softic_ presentation_Green Club_ENG.pdfDr. Admir Softic_ presentation_Green Club_ENG.pdf
Dr. Admir Softic_ presentation_Green Club_ENG.pdfAdmir Softic
 
Call Girls In Noida 959961⊹3876 Independent Escort Service Noida
Call Girls In Noida 959961⊹3876 Independent Escort Service NoidaCall Girls In Noida 959961⊹3876 Independent Escort Service Noida
Call Girls In Noida 959961⊹3876 Independent Escort Service Noidadlhescort
 
RSA Conference Exhibitor List 2024 - Exhibitors Data
RSA Conference Exhibitor List 2024 - Exhibitors DataRSA Conference Exhibitor List 2024 - Exhibitors Data
RSA Conference Exhibitor List 2024 - Exhibitors DataExhibitors Data
 
Call Now ☎️🔝 9332606886🔝 Call Girls ❤ Service In Bhilwara Female Escorts Serv...
Call Now ☎️🔝 9332606886🔝 Call Girls ❤ Service In Bhilwara Female Escorts Serv...Call Now ☎️🔝 9332606886🔝 Call Girls ❤ Service In Bhilwara Female Escorts Serv...
Call Now ☎️🔝 9332606886🔝 Call Girls ❤ Service In Bhilwara Female Escorts Serv...Anamikakaur10
 
Call Girls In Majnu Ka Tilla 959961~3876 Shot 2000 Night 8000
Call Girls In Majnu Ka Tilla 959961~3876 Shot 2000 Night 8000Call Girls In Majnu Ka Tilla 959961~3876 Shot 2000 Night 8000
Call Girls In Majnu Ka Tilla 959961~3876 Shot 2000 Night 8000dlhescort
 
PHX May 2024 Corporate Presentation Final
PHX May 2024 Corporate Presentation FinalPHX May 2024 Corporate Presentation Final
PHX May 2024 Corporate Presentation FinalPanhandleOilandGas
 
Cracking the Cultural Competence Code.pptx
Cracking the Cultural Competence Code.pptxCracking the Cultural Competence Code.pptx
Cracking the Cultural Competence Code.pptxWorkforce Group
 
BAGALUR CALL GIRL IN 98274*61493 ❤CALL GIRLS IN ESCORT SERVICE❤CALL GIRL
BAGALUR CALL GIRL IN 98274*61493 ❤CALL GIRLS IN ESCORT SERVICE❤CALL GIRLBAGALUR CALL GIRL IN 98274*61493 ❤CALL GIRLS IN ESCORT SERVICE❤CALL GIRL
BAGALUR CALL GIRL IN 98274*61493 ❤CALL GIRLS IN ESCORT SERVICE❤CALL GIRLkapoorjyoti4444
 
JAYNAGAR CALL GIRL IN 98274*61493 ❤CALL GIRLS IN ESCORT SERVICE❤CALL GIRL
JAYNAGAR CALL GIRL IN 98274*61493 ❤CALL GIRLS IN ESCORT SERVICE❤CALL GIRLJAYNAGAR CALL GIRL IN 98274*61493 ❤CALL GIRLS IN ESCORT SERVICE❤CALL GIRL
JAYNAGAR CALL GIRL IN 98274*61493 ❤CALL GIRLS IN ESCORT SERVICE❤CALL GIRLkapoorjyoti4444
 
Famous Olympic Siblings from the 21st Century
Famous Olympic Siblings from the 21st CenturyFamous Olympic Siblings from the 21st Century
Famous Olympic Siblings from the 21st Centuryrwgiffor
 

Dernier (20)

Mysore Call Girls 8617370543 WhatsApp Number 24x7 Best Services
Mysore Call Girls 8617370543 WhatsApp Number 24x7 Best ServicesMysore Call Girls 8617370543 WhatsApp Number 24x7 Best Services
Mysore Call Girls 8617370543 WhatsApp Number 24x7 Best Services
 
Katrina Personal Brand Project and portfolio 1
Katrina Personal Brand Project and portfolio 1Katrina Personal Brand Project and portfolio 1
Katrina Personal Brand Project and portfolio 1
 
Call Girls Zirakpur👧 Book Now📱7837612180 📞👉Call Girl Service In Zirakpur No A...
Call Girls Zirakpur👧 Book Now📱7837612180 📞👉Call Girl Service In Zirakpur No A...Call Girls Zirakpur👧 Book Now📱7837612180 📞👉Call Girl Service In Zirakpur No A...
Call Girls Zirakpur👧 Book Now📱7837612180 📞👉Call Girl Service In Zirakpur No A...
 
Call Girls Electronic City Just Call 👗 7737669865 👗 Top Class Call Girl Servi...
Call Girls Electronic City Just Call 👗 7737669865 👗 Top Class Call Girl Servi...Call Girls Electronic City Just Call 👗 7737669865 👗 Top Class Call Girl Servi...
Call Girls Electronic City Just Call 👗 7737669865 👗 Top Class Call Girl Servi...
 
Call Girls Kengeri Satellite Town Just Call 👗 7737669865 👗 Top Class Call Gir...
Call Girls Kengeri Satellite Town Just Call 👗 7737669865 👗 Top Class Call Gir...Call Girls Kengeri Satellite Town Just Call 👗 7737669865 👗 Top Class Call Gir...
Call Girls Kengeri Satellite Town Just Call 👗 7737669865 👗 Top Class Call Gir...
 
Quick Doctor In Kuwait +2773`7758`557 Kuwait Doha Qatar Dubai Abu Dhabi Sharj...
Quick Doctor In Kuwait +2773`7758`557 Kuwait Doha Qatar Dubai Abu Dhabi Sharj...Quick Doctor In Kuwait +2773`7758`557 Kuwait Doha Qatar Dubai Abu Dhabi Sharj...
Quick Doctor In Kuwait +2773`7758`557 Kuwait Doha Qatar Dubai Abu Dhabi Sharj...
 
👉Chandigarh Call Girls 👉9878799926👉Just Call👉Chandigarh Call Girl In Chandiga...
👉Chandigarh Call Girls 👉9878799926👉Just Call👉Chandigarh Call Girl In Chandiga...👉Chandigarh Call Girls 👉9878799926👉Just Call👉Chandigarh Call Girl In Chandiga...
👉Chandigarh Call Girls 👉9878799926👉Just Call👉Chandigarh Call Girl In Chandiga...
 
Call Girls Ludhiana Just Call 98765-12871 Top Class Call Girl Service Available
Call Girls Ludhiana Just Call 98765-12871 Top Class Call Girl Service AvailableCall Girls Ludhiana Just Call 98765-12871 Top Class Call Girl Service Available
Call Girls Ludhiana Just Call 98765-12871 Top Class Call Girl Service Available
 
Dr. Admir Softic_ presentation_Green Club_ENG.pdf
Dr. Admir Softic_ presentation_Green Club_ENG.pdfDr. Admir Softic_ presentation_Green Club_ENG.pdf
Dr. Admir Softic_ presentation_Green Club_ENG.pdf
 
Call Girls In Noida 959961⊹3876 Independent Escort Service Noida
Call Girls In Noida 959961⊹3876 Independent Escort Service NoidaCall Girls In Noida 959961⊹3876 Independent Escort Service Noida
Call Girls In Noida 959961⊹3876 Independent Escort Service Noida
 
(Anamika) VIP Call Girls Napur Call Now 8617697112 Napur Escorts 24x7
(Anamika) VIP Call Girls Napur Call Now 8617697112 Napur Escorts 24x7(Anamika) VIP Call Girls Napur Call Now 8617697112 Napur Escorts 24x7
(Anamika) VIP Call Girls Napur Call Now 8617697112 Napur Escorts 24x7
 
RSA Conference Exhibitor List 2024 - Exhibitors Data
RSA Conference Exhibitor List 2024 - Exhibitors DataRSA Conference Exhibitor List 2024 - Exhibitors Data
RSA Conference Exhibitor List 2024 - Exhibitors Data
 
Call Now ☎️🔝 9332606886🔝 Call Girls ❤ Service In Bhilwara Female Escorts Serv...
Call Now ☎️🔝 9332606886🔝 Call Girls ❤ Service In Bhilwara Female Escorts Serv...Call Now ☎️🔝 9332606886🔝 Call Girls ❤ Service In Bhilwara Female Escorts Serv...
Call Now ☎️🔝 9332606886🔝 Call Girls ❤ Service In Bhilwara Female Escorts Serv...
 
Call Girls In Majnu Ka Tilla 959961~3876 Shot 2000 Night 8000
Call Girls In Majnu Ka Tilla 959961~3876 Shot 2000 Night 8000Call Girls In Majnu Ka Tilla 959961~3876 Shot 2000 Night 8000
Call Girls In Majnu Ka Tilla 959961~3876 Shot 2000 Night 8000
 
Falcon Invoice Discounting platform in india
Falcon Invoice Discounting platform in indiaFalcon Invoice Discounting platform in india
Falcon Invoice Discounting platform in india
 
PHX May 2024 Corporate Presentation Final
PHX May 2024 Corporate Presentation FinalPHX May 2024 Corporate Presentation Final
PHX May 2024 Corporate Presentation Final
 
Cracking the Cultural Competence Code.pptx
Cracking the Cultural Competence Code.pptxCracking the Cultural Competence Code.pptx
Cracking the Cultural Competence Code.pptx
 
BAGALUR CALL GIRL IN 98274*61493 ❤CALL GIRLS IN ESCORT SERVICE❤CALL GIRL
BAGALUR CALL GIRL IN 98274*61493 ❤CALL GIRLS IN ESCORT SERVICE❤CALL GIRLBAGALUR CALL GIRL IN 98274*61493 ❤CALL GIRLS IN ESCORT SERVICE❤CALL GIRL
BAGALUR CALL GIRL IN 98274*61493 ❤CALL GIRLS IN ESCORT SERVICE❤CALL GIRL
 
JAYNAGAR CALL GIRL IN 98274*61493 ❤CALL GIRLS IN ESCORT SERVICE❤CALL GIRL
JAYNAGAR CALL GIRL IN 98274*61493 ❤CALL GIRLS IN ESCORT SERVICE❤CALL GIRLJAYNAGAR CALL GIRL IN 98274*61493 ❤CALL GIRLS IN ESCORT SERVICE❤CALL GIRL
JAYNAGAR CALL GIRL IN 98274*61493 ❤CALL GIRLS IN ESCORT SERVICE❤CALL GIRL
 
Famous Olympic Siblings from the 21st Century
Famous Olympic Siblings from the 21st CenturyFamous Olympic Siblings from the 21st Century
Famous Olympic Siblings from the 21st Century
 

An intro to cqrs

  • 1. DDD South West 2An Introduction to CQRS approaches to system architecture @NeilRobbins neil@computer.org
  • 2. Aims An overview of CQRS UI Command Handling View Handling How to write an Event Sourced DDD system The command handling bit
  • 3. But first some code To Visual Studio!
  • 4. What’s wrong with this? public class Event { public string Name { get; set; } public int Venue { get; set; } public DateTime Date { get; set; } public IEnumerable<Session> Sessions { get; set; } } public class Session { public PresentationPresentation { get; set; } public string Location { get; set; } public DateTime Time { get; set; } }
  • 5. But what about Queries? They’re just queries They support the UI which should provide a Decision Support System
  • 6. Intentful UI Shopping Cart Service Command Command Ratings Service Command Command Product Images Service Command Command Command Buying Choices Service Offers Service Bought Together Service
  • 7. Intentful UI Captures Intent Aligns with commands Uses the query infrastructure For display For decision support Commands should succeed Will contain logic, is typically rich
  • 8. Some Slides Big picture & background stuff!
  • 9. Façadelient Bus Commands Eventually Consistent Queries Handler
  • 10. Subscriber Subscriber Publisher Subscribers Subscriber
  • 11. ID : 123 Name : The Art of War Author: Sun Tzu ISBN: 1234ABCD5678 Event: BookIsbnChanged NewValue: 4321DCBA8765
  • 12. …there are times when we don't just want to see where we are, we also want to know how we got there http://martinfowler.com/eaaDev/EventSourcing.html
  • 13. Time to See Some Code You didn’t think I’d make you watch me type did you?
  • 14. Coding for EventSourcing namespaceProgNetDemo { public classCatalogItem { } }
  • 15. A Command Method namespaceProgNetDemo { public classCatalogItem { public void Retire() { } } }
  • 16. Some State To Change namespaceProgNetDemo { public classCatalogItem { privatebool _retired; public void Retire() { } } }
  • 17. Guard the Mutation namespaceProgNetDemo { public classCatalogItem { privatebool _retired; public void Retire() { if (!_retired) thrownewInvalidOperationException(); } } }
  • 18. Make the State Mutation A Domain Event namespaceProgNetDemo { public classCatalogItem { privatebool _retired; public void Retire() { if (!_retired) thrownewInvalidOperationException(); ApplyEvent(new RetiredEvent(_id)); } } }
  • 19. Need an Identifier for the Aggregate public classCatalogItem { privatebool _retired; privateGuid_id; public void Retire() { if (!_retired) thrownewInvalidOperationException(); ApplyEvent(new RetiredEvent(_id)); } }
  • 20. Create the Event publicclassRetiredEvent { privatereadonlyGuid _id; publicRetiredEvent(Guid id) { _id = id; } }
  • 21. Need to be Able to Apply the Event public classCatalogItem { privatebool _retired; privateGuid_id; public void Retire() { if (!_retired) thrownewInvalidOperationException(); ApplyEvent(new RetiredEvent(_id)); } }
  • 22. Create a Base Class public classAggregateRoot { protected voidApplyEvent(Event @event) { } } We’ll need to handle more than just the one type of event!
  • 23. Create the Event Type public classEvent { }
  • 24. Have our RetiredEvent Inherit From the Base Type publicclassRetiredEvent : Event { privatereadonlyGuid _id; publicRetiredEvent(Guid id) { _id = id; } }
  • 25. Still Need to Mutate the State public classCatalogItem : AggregateRoot { privatebool _retired; privateGuid_id; public void Retire() { if (!_retired) thrownewInvalidOperationException(); ApplyEvent(new RetiredEvent(_id)); } }
  • 26. Create a Method to Handle the State Change From the Event public classCatalogItem : AggregateRoot { privatebool _retired; privateGuid_id; public void Retire() { if (!_retired) thrownewInvalidOperationException(); ApplyEvent(new RetiredEvent(_id)); } private voidApplyRetiredEvent(RetiredEvent @event) { _retired = true; } }
  • 27. Done!? public classCatalogItem : AggregateRoot { privatebool _retired; privateGuid_id; public void Retire() { if (!_retired) thrownewInvalidOperationException(); ApplyEvent(new RetiredEvent(_id)); } private voidApplyRetiredEvent(RetiredEvent @event) { _retired = true; } }
  • 28. Need to Connect the Event with the Handler public classCatalogItem : AggregateRoot { privatebool _retired; privateGuid_id; publicCatalogItem() { RegisterHandler<RetiredEvent>(ApplyRetiredEvent); } public void Retire() { if (!_retired) thrownewInvalidOperationException(); ApplyEvent(new RetiredEvent(_id)); } private voidApplyRetiredEvent(RetiredEvent @event) { _retired = true; } }
  • 29. Allow Handlers to be Registered public classAggregateRoot { protected voidRegisterHandler<TEvent>(AppliesEvent<TEvent> handler) whereTEvent : Event { } protected voidApplyEvent(Event @event) { } }
  • 30. Create the Delegate Signature public delegate voidAppliesEvent<TEvent>(TEvent @event) where TEvent : Event; public classAggregateRoot { protected voidRegisterHandler<TEvent>(AppliesEvent<TEvent> handler) whereTEvent : Event { } protected voidApplyEvent(Event @event) { } }
  • 31. Need to Maintain the Registry public delegate voidAppliesEvent<TEvent>(TEvent @event) where TEvent : Event; public classAggregateRoot { private readonlyIDictionary<Type, Action<Event>> _handlerRegistry; protected voidRegisterHandler<TEvent>(AppliesEvent<TEvent> handler) whereTEvent : Event { var castHandler = DelegateAdjuster.CastArgument<Event, TEvent>(e => handler(e)); } protected voidApplyEvent(Event @event) { } }
  • 32. Delegate Adjuster:From Greg’s Blog public class DelegateAdjuster { public static Action<TBase> CastArgument<TBase, TDerived>(Expression<Action<TDerived>> source) whereTDerived : TBase { if (typeof(TDerived) ==typeof(TBase)) { return (Action<TBase>)((Delegate)source.Compile()); } ParameterExpressionsourceParameter = Expression.Parameter(typeof(TBase),"source"); varresult = Expression.Lambda<Action<TBase>>( Expression.Invoke( source, Expression.Convert(sourceParameter, typeof(TDerived))), sourceParameter); return result.Compile(); } }
  • 33. Need to Maintain the Registry public delegate voidAppliesEvent<TEvent>(TEvent @event) where TEvent : Event; public classAggregateRoot { private readonlyIDictionary<Type, Action<Event>> _handlerRegistry; protected voidRegisterHandler<TEvent>(AppliesEvent<TEvent> handler) whereTEvent : Event { var castHandler = DelegateAdjuster.CastArgument<Event, TEvent>(e => handler(e)); _handlerRegistry.Add(typeof(TEvent), castHandler); } protected voidApplyEvent(Event @event) { } }
  • 34. Need to Apply the Event Still public delegate voidAppliesEvent<TEvent>(TEvent @event) where TEvent : Event; public classAggregateRoot { private readonlyIDictionary<Type, Action<Event>> _handlerRegistry; protected voidRegisterHandler<TEvent>(AppliesEvent<TEvent> handler) whereTEvent : Event { var castHandler = DelegateAdjuster.CastArgument<Event, TEvent>(e => handler(e)); _handlerRegistry.Add(typeof(TEvent), castHandler); } protected voidApplyEvent(Event @event) { Action<Event> handler; if (!_handlerRegistry.TryGetValue(@event.GetType(), out handler)) { throw newInvalidOperationException(); } handler(@event); } }
  • 35. Need to Track Applied Events public delegate voidAppliesEvent<TEvent>(TEvent @event) where TEvent : Event; public classAggregateRoot { private readonlyIDictionary<Type, Action<Event>> _handlerRegistry; private readonlyICollection<Event> _events; protected voidRegisterHandler<TEvent>(AppliesEvent<TEvent> handler) whereTEvent : Event { var castHandler = DelegateAdjuster.CastArgument<Event, TEvent>(e => handler(e)); _handlerRegistry.Add(typeof(TEvent), castHandler); } protected voidApplyEvent(Event @event) { Action<Event> handler; if (!_handlerRegistry.TryGetValue(@event.GetType(), out handler)) { throw newInvalidOperationException(); } handler(@event); _events.Add(@event); } }
  • 36. All done now??? public classCatalogItem : AggregateRoot { privatebool _retired; privateGuid_id; publicCatalogItem() { RegisterHandler<RetiredEvent>(ApplyRetiredEvent); } public void Retire() { if (!_retired) thrownewInvalidOperationException(); ApplyEvent(new RetiredEvent(_id)); } private voidApplyRetiredEvent(RetiredEvent @event) { _retired = true; } } Could use a convention & just make the AggregateRoot declare which events it produces
  • 37. Not Quite Need to Expose the events for persistence & publishing Put a GetChanges() method on the AggregateRoot base class Need to be able to rebuild the Aggregate from history Put a LoadFromHistory(IEnumerable<Event> events) method on the AggregateRoot base class Reapply the events Don’t track them as changes – overload apply event protected voidApplyEvent(Event @event, booltrackAsChange) if (add) _events.Add(@event); Possibly memento pattern for snapshoting See Mark Nijhof’s blog & sample code on GitHub
  • 38. Back to the Whiteboard! Some more on Query Stores
  • 39. Some Other Benefits of Event Sourcing Already We can build new stores for new services, we have the full set of available information ready We can rebuild stores for existing services We use the same mechanism for our Query Stores as we use for any other service in the Enterprise More Granular Service Boundaries More Explicit Boundaries We aren’t just restricted to storing the Events Can send Emails based on them Can perform Complex Event Processing … The worlds your Oyster, you have the RAW MATERIAL
  • 40. Some Other Benefits of Event Sourcing Also A Very Provable Audit Log Very Simple Horizontal Scaling More Granular Service Boundaries More Explicit Boundaries Can Replay Events in Debugging Scenarios Suits Behaviour Based Testing & Outside-In Development
  • 41. NO SILVER BULLETS The coding is the EASY BIT Don’t need a grand framework The thinking & conversations is the HARD BIT
  • 42. Referenced Material/Links Greg Youngs: Course – http://bit.ly/gregscourse Blog – http://bit.ly/gregyoungsblog UdiDahans: Course – http://bit.ly/udiscourse Blog – http://bit.ly/udisblog Mark Nijhof’s sample code http://github.com/MarkNijhof/Fohjin

Notes de l'éditeur

  1. I’m afraid my job title has the word architect in it – so we’re off to an ivory tower for this bit 
  2. Boundaries are Explicit Acknowledge potential cost (perf &amp; dev) of going between services: geographical cost trust boundaries execution environments
  3. Which might seem a strange place to begin a talk on CQRS!Every button, link the lot – is a command of interest – though not all may be handled in the same way.
  4. Which might seem a strange place to begin a talk on CQRS!Every button, link the lot – is a command of interest – though not all may be handled in the same way.
  5. Which might seem a strange place to begin a talk on CQRS!Every button, link the lot – is a command of interest – though not all may be handled in the same way.
  6. Maintaining the ViewState
  7. Capturing all state changes made to an object as Event ObjectsAdvantages:Rebuild state from eventsTemporal Queries – rebuild state to a point in timeDebugging – replay events that led to a problemSnapshotsDisadvantagesCan look a bit magical