Showing posts with label CQRS. Show all posts
Showing posts with label CQRS. Show all posts

Sunday, May 12, 2013

CQRS Simplified - Part 2 (Commands & Command Handlers)


Every imperative operation in the system represents a command in CQRS. A Command is simply a DTO-type of object that contains the data necessary to make one specific change to the state of the system. The service method that accepts a command does not returns any values. In case of WCF services, if the command execution failed, a fault contract exception is thrown. The method that accepts the command is responsible for validating the command via a command validator object (remember SRP :)) before passing it to a handler object to execute the command.

Below is an example of a DTO that encapsulates the command information in our sample. Note that the commands have an Identity object in our sample.
public class RespondToRsvpCommand : ICommand
{
    public Guid RsvpReferenceId { get; set; }
    public bool Response { get; set; }


    public override string ToString()
    {
        return "Respond to RSVP";
    }
}

The command handlers are responsible for executing the commands. You can normally group commands to an aggregate in a command handler as given below.

public class RsvpCommandHandler : ICommandHandler<RespondToRsvpCommand>, ICommandHandler<ConfigureRsvpCommand>,
                                    IDependencyResolver
{
    [InjectionConstructor]
    public RsvpCommandHandler()
    {
        ResolveDependencies();
    }

    private ICommandValidator<RespondToRsvpCommand> RespondToRsvpCommandValidator { get; set; }

    private ICommandValidator<ConfigureRsvpCommand> ConfigureRsvpCommandValidator { get; set; }

    public void Process(RespondToRsvpCommand command)
    {
        //RSVP processing logic goes here
    }

    public bool Validate(ConfigureRsvpCommand command)
    {
        return true;
    }

    public void Process(ConfigureRsvpCommand command)
    {
        //throw new NotImplementedException();
    }

    public bool IsValid(RespondToRsvpCommand command)
    {
        return RespondToRsvpCommandValidator.Validate(command);
    }

    public bool IsValid(ConfigureRsvpCommand command)
    {
        return ConfigureRsvpCommandValidator.Validate(command);
    }

    public void ResolveDependencies()
    {
        RespondToRsvpCommandValidator = Container.Current.Resolve<ICommandValidator<RespondToRsvpCommand>>();
        ConfigureRsvpCommandValidator = Container.Current.Resolve<ICommandValidator<ConfigureRsvpCommand>>();
    }
}

As you can see, I've used the ICommandValidator instances to validate the respective commands in the context. I've also used the unity dependency container as my dispatcher object to dispatch the respective command handlers.

Next : Events

Sunday, May 5, 2013

CQRS Simplified – Part 1 (Introduction)


CQRS is an object oriented architectural pattern built on the principle that every method should either be a command that performs an action, or a query that returns data to the client, but not both.

A typical CQRS scenario involves 2 DB's, a write DB which is used to store transitional data for long running processes.  For a process where a service expects multiple messages, it needs a way to temporary store data before the all the messages arrives. For e.g. to make a customer a preferred customer needs an approval from the management, which takes some time to process the request. The service will need a temporary storage for the preferred customer state change request till the approval comes. The write DB is used to store these kinds of data. The Read DB is not updated till the approval comes.

When the approval finally comes, the service will take the customer information from the write DB, complete the registration process and write it to the read DB. At this time, the temporary customer information in the write DB has done its job and can be removed from the write DB. For simpler process such as change customer first name, the change can be written to the read DB right away. Writing to the write DB is not required because there is no temporary data in this case.

This simple approach brings following benefits (from Rinat Abdullin's blog)
  • Denormalized query persistence is optimized for the reads (which usually make up the most of the persistence IO) resulting in better performance and user experience;
  • We can optimize our read side for the needs of the UI (i.e.: fetching dashboard for the user in a single query) which will result in better development experience and less risk of breaking something on the write side.
  • Read side can be put on some cloud storage, which is inherently optimized for the reads, could be partitioned, replicated and even distributed via CDN;
  • By offloading data reads to synchronous queries we automatically increase the performance of the write side - now it has lower stress and lower probability of hitting a deadlock

This blog is an attempt to implement the principles of CQRS in a very simple way, for demonstrating the concepts of CQRS like:
  • Commands
  • Command Handlers (validation and execution)
  • Queries
  • Query parameters and Query results
  • Command Dispatchers.