Journey to CQS – Part 1

I have been using Command–query separation (CQS) concept in most of my projects for almost a year. So far I am very happy with the outcome. My projects are more manageable, Flexible to changes and none of the classes showing any tendency to become large class with too many methods and dependencies. So I decided to share the way I am applying CQS in my projects. Main concept of CQS is to separate the write (Command) and read (Query) part of your application.

Before showing CQS in action, lets see some key components I use and their roles.

Command

Generally Command is a DTO type of class that you have to write to define the intention you want to achieve. For example if you are implementing a functionality to handle order from user you most probably want to define a command named “PlaceOrder”. As from the name its is clear that it is command and also its intention.

Command Dispatcher

This is top level class that generally used from controller or system Entry point. The responsibility of the command dispatcher is the find the appropriate handler that can handle the command. So your controller don’t have direct dependency or know about anything how that command should process.

Command Handler

You need to define a command handler for your command and command dispatcher will call this class to process the command. Generally here you will define all you code to process a command. For example, create a domain object from the command and call repository to save in database.

Validator

Validation is not directly related to CQS but important part of every application. You can define multiple validators for a command. We use Decorator pattern to decorate a commandhandler. The decorator executed all validators for the command and if all of them pass then the original commandhandler is called to process the command. Otherwise the decorator return a command result with all validation errors.

Event

Event is a DTO class that contains all possible information about an event. For example when a order placed successfully then we can raise and event named “OrderPlaced” and this event should contain the newly created order id. So that all the subscribers for this event can retrieve the order details to do something with that.

Event Handler

Event handler generally contains logic to process any event. You can have multiple event handlers for a single event. For example when a “OrderPlaced” event occurred you may want to push this event to any kind of Message Bus like MSMQ/RabbitMQ or Windows Service Bus etc. So that other process can prepare invoice for that order. And you may also want remove a cache key immediately so that user don’t see stale data. To achieve that you need to write two Eventhandlers for that event rather than doing everything in one place.

If you like you can move all payment and invoicing in other process using messaging system (Fire and forget scenario) but that’s a different discussion and may not applicable for all type of applications.

Event Dispatcher

Event dispatcher’s responsibility is to find all event handlers that subscribed to specific event and then execute them. Generally command handler create an event and use EventDispatcher to dispatch that event to all subscribed event handlers.

Show me some code

Enough theory so far. Lets see some code in action. Lets say we have following requirements:

As a user I should able to add book
– book title cannot be empty
– book title must be less than 256 characters
– price must be greater than 0
– should not allow to add a book with existing ISBN number
– email should be sent to members notifying a new title is available

First we need to define what we want to do here in other word intention. Our intention here is to create a book. So a good command name could be “CreateBook”. Because this clearly tells what this command for. Now decide what we need from the end user to create a book. Let say to create a book the user needs to provide Title, ISBN and price of the book.

It is important to realize that main purpose of command is the intention not the properties of command. Properties of command is the second requirement and reason is most of the time to fulfill a command we need some information from user. For example if you want to delete all books in system you might define a command as “DeleteAllBooks” and that command doesn’t need any property at all. The command itself is enough to tell that you want to delete all books in the system.

Lets define the command class to create a book:


namespace Sample.Core.Commands
{
	public class CreateBook : ICommand
	{
		public string Title { get; set; }
		public string Isbn { get; set; }
		public decimal Price { get; set; }
	}
}

Now we need a controller which will take user request. Controllers responsibility here is to create a command object from user request and then tell command dispatcher to dispatch the command and give back a reply. In many situation you might don’t need any reply (Fire and forget). That means controller has a dependency on command dispatcher and that’s it. Controller doesn’t know who can handle this command and how to handle this command. That save us from writing lot of code and dependency on controller. Controller just do one thing and do it right. Lets see a controller in action and also showing how dispatchers are registered in IOC container.


namespace Sample.WebUI.Api.V1.Controllers
{
    [RoutePrefix("api/v1/cqrs/books")]
    public class BooksController : ApiController
    {
        private readonly ICommandDispatcher _commandDispatcher;

        public BooksController(ICommandDispatcher commandDispatcher)
        {
            _commandDispatcher = commandDispatcher;
        }

        [Route(Name = "CreateBook")]
        public async Task<IHttpActionResult> Post([FromBody] CreateBook createBook)
        {
            var reply = await _commandDispatcher.DispatchAsync<CreateBook, CommandReply<long>>(createBook);

            return this.CommandResult(reply, () => Url.BookDetails(reply.Data));
        }
    }
}


namespace Sample.WebUI.Ioc.Modules
{
	// This bindings make all dispatchers available to controllers
	public class DispatchersModule : NinjectModule
	{
	    public override void Load()
	    {
	        Bind<Lib.SimpleCqrs.Extended.IDependencyResolver>().ToMethod(x => new DependencyResolver(x.Kernel)).InSingletonScope();

	        Bind<ICommandDispatcher>().To<CommandDispatcher>().InSingletonScope();
	        Bind<IQueryDispatcher>().To<QueryDispatcher>().InSingletonScope();
	        Bind<IEventDispatcher>().To<EventDispatcher>().InSingletonScope();
	    }
	}
}

As you can see the controller is very thin and hardly has any logic in here. The code is also identical across all controllers and don’t has dependencies on lot of other classes. The command dispatcher will return the new book id that’s why in the signature we used “CommandReply” and use the id to build location header of the new resource. CommandReply is a simple poco that contains whether a command was successful or not, result data and collection of errors if any validation failed.

We didn’t define any commandhandler yet so this code will throw error because command dispatcher will not find any appropriate command handler for “CreateBook” command. So lets define a command handler and register the handler in IOC container.


namespace Sample.Infrastructure.CommandHandlers
{
    public class CreateBookHandler : IAsyncCommandHandler<CreateBook,CommandReply<long>>
    {
        private readonly IBooksRepository _repository;
        private readonly IMapper _mapper;

        public CreateBookHandler(IBooksRepository repository, IMapper mapper)
        {
            _repository = repository;
            _mapper = mapper;
        }

        public async Task<CommandReply<long>> HandleAsync(CreateBook command)
        {
            // map the command to domain object
            var book = _mapper.Map<CreateBook, Book>(command);

            await _repository.InsertAsync(book);

            return new CommandReply<long>
            {
                Succeed = true,
                Data = book.Id
            };
        }
    }
}

Okay now I have a command handler for CreateBook. Lets register command handler in IOC container so the CommandDispatcher can find this command handler. I am using Ninject as my DI framework.

namespace Sample.WebUI.Ioc.Modules
{
    public class CommandsModule : NinjectModule
    {
        public override void Load()
        {
            Bind(typeof(IAsyncCommandHandlerFactory<,>)).To(typeof(AsyncCommandHandlerFactory<,>));

            Bind<IAsyncCommandHandler<CreateBook, CommandReply<long>>>().To<CreateBookHandler>();
        }
    }
}

Okay our API endpoint is ready to use and you can create new book. But what about our other requirements. We need to do the validations. Lets define the validators and attach them using IOC container for this command.


namespace Sample.Infrastructure.Commands.Validators
{
    public class CreateBookInputValidator : IAsyncValidator<CreateBook>
    {
        public async Task<ValidationResult> ValidateAsync(CreateBook command)
        {
            return await Task.FromResult(
                RuleChecker.For(command)
                    .Property(x => x.Title)
                        .ErrorCode(100)
                        .ErrorMessage("Title is required")
                        .NotEmpty()
                    .Property(x => x.Title)
                        .ErrorCode(101)
                        .ErrorMessage("Title must be within 256 characters")
                        .Should(x => x.NullSafe().Length <= 256)
                    .Property(x => x.Price)
                        .ErrorCode(102)
                        .ErrorMessage("Price must be greater than 0")
                        .Should(x => x > 0)
                    .Done()
                    .ValidationResult(1000)
            );
        }
    }
}


Lets check the other validator that validates duplicate ISBN.


namespace Sample.Infrastructure.Commands.Validators
{
    public class CreateBookUniqueValidator : IAsyncValidator<CreateBook>
    {
        private readonly IBooksRepository _repository;

        public CreateBookUniqueValidator(IBooksRepository repository)
        {
            _repository = repository;
        }

        public async Task<ValidationResult> ValidateAsync(CreateBook command)
        {
            var exists = await _repository.IsbnExistsAsync(command.Isbn, null);

            return await Task.FromResult(
                    RuleChecker.For(command)
                        .Property(x => x.Isbn)
                        .ErrorCode(1001)
                        .ErrorMessage("ISBN already exists.")
                        .Should(s => !exists)
                        .Done()
                        .ValidationResult(1001)
                );
        }
    }
}

Okay I defined the validators but those need to register in IOC container so that they can be executed before our commandhandler get chance to execute.

public class CommandsModule : NinjectModule
{
    public override void Load()
    {
        Bind(typeof(IAsyncCommandHandlerFactory<,>)).To(typeof(AsyncCommandHandlerFactory<,>));

        Bind<IAsyncCommandHandler<CreateBook, CommandReply<long>>>().To<CreateBookHandler>();
        Bind<IAsyncValidator<CreateBook>>().To<CreateBookInputValidator>().InSingletonScope();
        Bind<IAsyncValidator<CreateBook>>().To<CreateBookUniqueValidator>();
    }
}

Now all my validations are in place. Lets concentrate on our next requirement. That is to notify members by email. As this is a long running process and doesn’t need to done immediately so we will send an event to our Messaging system [Can be Windows Service Bus or RabbitMQ or Amazon SNS ]. A message receiver app can process the event, find all subscribed members and send emails to all of them. Sending event to Messaging system is out of scope of this post. We will achieve this requirement using Event.

Lets see the Event part of the system. First define an Event and EventHandler that CreateBook command handler should raise.

namespace Sample.Core.Events
{
    public class BookCreated : IEvent
    {
        public long Id { get; set; }
    }
}

Event Handler code is as below:


namespace Sample.Infrastructure.Commands.Events
{
    public class SendMessageOnBookCreatedHandler : IAsyncEventHandler<BookCreated>
    {
        private readonly ILogger _logger;
        private readonly IMessageSender _sender;

        public SendMessageOnBookCreatedHandler(ILogger logger, IMessageSender sender)
        {
            _logger = logger;
            _sender = sender;
        }

        public Task HandleAsync(BookCreated input)
        {
            _logger.Debug("Sending email to members who want to be notified on new book available {0}", input.Id);

            return _sender.SendAsync(input);
        }
    }
}

You can define more than one event handler for an event and raise them from your command handler as below. Update the CreateBookCommandHandler class as below:


public class CreateBookHandler : IAsyncCommandHandler<CreateBook,CommandReply<long>>
{
    private readonly IBooksRepository _repository;
    private readonly IMapper _mapper;
    private readonly IEventDispatcher _eventDispatcher;

    public CreateBookHandler(IBooksRepository repository, IMapper mapper, IEventDispatcher eventDispatcher)
    {
        _repository = repository;
        _mapper = mapper;
        _eventDispatcher = eventDispatcher;
    }

    public async Task<CommandReply<long>> HandleAsync(CreateBook command)
    {
        var book = _mapper.Map<CreateBook, Book>(command);

        await _repository.InsertAsync(book);

        await _eventDispatcher.DispatchAsync(new BookCreated{ Id = book.Id });

        return new CommandReply<long>
        {
            Succeed = true,
            Data = book.Id
        };
    }
}

We added a dependency of IEventDispatcher in our CreateBookCommandHandler and after adding the book successfully we call eventdispatcher to find all evenhandlers subscribed for the event “BookCreated” and execute them. In order to make our eventhandler available to eventdispatcher we need to register the handlers in IOC cotnainer as below:

Bind<IAsyncEventHandler<BookCreated>>().To<SendMessageOnBookCreatedHandler>();

Now whenever a book created successfully a event sent to messagebus and another receiver app / windows service can process them and send email to users.

Hope this will give you an idea how CQS can make your development much disciplined, well structured, flexible and loosely coupled. Next part I will try to show how the Query part of CQS works. That’s all for today. Happy coding 🙂

Advertisements

3 thoughts on “Journey to CQS – Part 1

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s