Recently I got a chance to implement the command query pattern. Here is my experience on this:
Requirement:
Implement an event system for promoting events that are happening at different places in the town. An administrator can create an event, update it and cancel it. Users can rsvp to the event.
Thought Process:
Although the requirement is a one liner, there are a couple of things we can deduce:
1. There needs to be a flow to create the event
2. Flow to update an event
3. Flow to cancel the event (this might be the same as (2) above in which we update the status of the event)
4. We need a way to find events to be shown to the user (lets say there were business rules around what needs to be shown to the user)
Overall, it looks like there are two types of things we are trying to do here:
a. Acting on events (create or update)
b. Querying for events (find or search)
Solution Approaches:
There were a couple of approaches that I thought we could take:
1. Implement a single service (EventService) that has public methods for individual operations discussed above.
2. Separate out functionality into actions and queries and implement two components, one which takes care of performing actions on the event and the second which performs search functionality. This is the Command Query pattern.
I liked approach (2) because it seemed to me that it is clearly separating concerns into individually managed components. This also helps reducing dependencies and making code more unit testable. This is because the search component won't need dependencies that are used for data manipulation (e.g. repositories that have methods that call stored procs for creating/updating data), and on the other hand the data manipulation component would not need dependencies that deal with data searching (the data manipulation would essentially work based off of primary keys like eventId and would not need to search for it). This reduces coupling in the system, which is a good to have thing in a well designed system.
Here is some sample C# code demonstrating the structure of this approach:
//Domain object
public class Event
{
public int EventId {get; set;}
public string EventName {get; set;}
//...other properties such as description, startdate, enddate etc...
}
//The command
public class EventCommand
{
//DI constructor
public EventCommand(Dependecy1, Dependency2.....){//implement}
public virtual void CreateEvent(Event ev){//implement}
public virtual void UpdateEvent(Event ev) {//implement}
public virtual void RespondToEvent(Event ev, User u) {//implement}
}
//The Query
public class EventQuery
{
//DI constructor
public EventQuery(Dep1, Dep2..) {//implement}
public virtual IEnumerable<Event> FindEventsByName(string name) {//implement}
public virtual Event FindEventById(int eventId) {//implement}
public virtual IEnumerable<Event> FindEventsBySomeBusinessRule(string bruleXml){//implement}
}
//Usage - in some mvc controller. This Mvccontroller would have EventQuery dependency injected
//this is what EvtQ is in the code below
public ActionResult GetEvent(int eventId)
{
Event ev = EvtQ.FindEventById(eventId); //this line can also go in the viewmodelbuilder
return View(//someviewmodelbuilderreturnedviewmodel);
}
You can also implement individual unit test files for the EventCommand and EventQuery.
In my opinion, command query makes code less coupled and more readable. There might be some design issues while using this pattern in a closely knit multi-threaded system, but it is a great pattern to use in simple, straight forward implementations, where you want your solution to be less messy and more manageable.
Requirement:
Implement an event system for promoting events that are happening at different places in the town. An administrator can create an event, update it and cancel it. Users can rsvp to the event.
Thought Process:
Although the requirement is a one liner, there are a couple of things we can deduce:
1. There needs to be a flow to create the event
2. Flow to update an event
3. Flow to cancel the event (this might be the same as (2) above in which we update the status of the event)
4. We need a way to find events to be shown to the user (lets say there were business rules around what needs to be shown to the user)
Overall, it looks like there are two types of things we are trying to do here:
a. Acting on events (create or update)
b. Querying for events (find or search)
Solution Approaches:
There were a couple of approaches that I thought we could take:
1. Implement a single service (EventService) that has public methods for individual operations discussed above.
2. Separate out functionality into actions and queries and implement two components, one which takes care of performing actions on the event and the second which performs search functionality. This is the Command Query pattern.
I liked approach (2) because it seemed to me that it is clearly separating concerns into individually managed components. This also helps reducing dependencies and making code more unit testable. This is because the search component won't need dependencies that are used for data manipulation (e.g. repositories that have methods that call stored procs for creating/updating data), and on the other hand the data manipulation component would not need dependencies that deal with data searching (the data manipulation would essentially work based off of primary keys like eventId and would not need to search for it). This reduces coupling in the system, which is a good to have thing in a well designed system.
Here is some sample C# code demonstrating the structure of this approach:
//Domain object
public class Event
{
public int EventId {get; set;}
public string EventName {get; set;}
//...other properties such as description, startdate, enddate etc...
}
//The command
public class EventCommand
{
//DI constructor
public EventCommand(Dependecy1, Dependency2.....){//implement}
public virtual void CreateEvent(Event ev){//implement}
public virtual void UpdateEvent(Event ev) {//implement}
public virtual void RespondToEvent(Event ev, User u) {//implement}
}
//The Query
public class EventQuery
{
//DI constructor
public EventQuery(Dep1, Dep2..) {//implement}
public virtual IEnumerable<Event> FindEventsByName(string name) {//implement}
public virtual Event FindEventById(int eventId) {//implement}
public virtual IEnumerable<Event> FindEventsBySomeBusinessRule(string bruleXml){//implement}
}
//Usage - in some mvc controller. This Mvccontroller would have EventQuery dependency injected
//this is what EvtQ is in the code below
public ActionResult GetEvent(int eventId)
{
Event ev = EvtQ.FindEventById(eventId); //this line can also go in the viewmodelbuilder
return View(//someviewmodelbuilderreturnedviewmodel);
}
You can also implement individual unit test files for the EventCommand and EventQuery.
In my opinion, command query makes code less coupled and more readable. There might be some design issues while using this pattern in a closely knit multi-threaded system, but it is a great pattern to use in simple, straight forward implementations, where you want your solution to be less messy and more manageable.
No comments:
Post a Comment