Repositories Revisited (and why CQRS is better)

09 Sep 2017

TLDR: I still don’t like Repositories!

Recently I had a discussion with a commenter on my The problems with, and solutions to Repositories post, and felt it was worth expanding on how I don’t use repositories.

My applications tend to use the mediator pattern to keep things decoupled (using the Mediatr library), and this means that I end up with “handler” classes which process messages; they load something from storage, call domain methods, and then write it back to storage, possibly returning some or all the data.

For example you could implement a handler to update the tags on a toggle class like so:

public class UpdateToggleTagsHandler : IAsyncRequestHandler<UpdateToggleTagsRequest, UpdateToggleTagsResponse>
{
    private readonly GetToggleQuery _getToggle;
    private readonly SaveToggleCommand _saveToggle;

    public UpdateToggleTagsHandler(GetToggleQuery getToggle, SaveToggleCommand saveToggle)
    {
        _getToggle = getToggle;
        _saveToggle = saveToggle;
    }

    public async Task<UpdateToggleTagsResponse> Handle(UpdateToggleTagsRequest message)
    {
        var toggle = await _getToggle.Execute(message.ToggleID);

        toggle.AddTag(message.Tag);

        await _saveToggle(toggle);

        return new UpdateToggleTagsResponse
        {
            Tags = toggle.Tags.ToArray()
        };
    }
}

Note how we use constructor injection to get a single command and a single query, and that the business logic is contained within the Toggle class itself, not the Handler.

By depending on commands and queries rather than using a repository, we can see at a glance what the UpdateToggleTagsHandler requires in the way of data, rather than having to pick through the code and figure out which of 20 methods on a repository is actually being called.

The actual domain classes (in this case, the Toggle class) know nothing of storage concerns. As I use EventSourcing a lot, the domain classes just need a few methods to facilitate storage: applying events, fetching pending events, and clearing pending events. For non EventSourced classes, I tend to use the Memento pattern: each class implements two methods, one to load from a plain object, one to write to the same plain object.

If your handler starts needing many commands or many queries passed in, it’s a pretty good indication that your design has a weakness which will probably need refactoring. This is harder to notice when using repositories as you might still only have a single constructor parameter, but be calling tens of methods on it.

Hopefully this provides a bit more reasoning behind my dislike of repositories, and how I try to implement alternatives.

design, cqrs, architecture

« Serilog LogContext with StructureMap and SimpleInjector Testing Containers or Test Behaviour, Not Implementation »