Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CQRS code duplication in commands

I have a question about code duplication in the command side of the CQRS principle.

Been following the articles from:

https://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=91 https://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=92

It seems to me that this approach of separating each command in it's own class is going to give some code duplication when retrieving the entities from the data store.

A bit contrived perhaps but let's say for example I have a command where I want to reset a users password given his email-address and a command where I want to update the user's last login date.

public class ResetPasswordCommandHandler : CommandHandler<ResetPasswordCommand>
{
    public override void Execute(ResetPasswordCommand command)
    {
       **// duplication here**
        var user = from c in db.Users
            where c.EmailAddress = command.EmailAddress
            select c;

        user.EmailAddress = command.EmailAddress;
        ...
        db.Save();
   }
}

public class UpdateLastLoginCommandHandler : CommandHandler<UpdateLastLoginCommand>
{
    public override void Execute(UpdateLastLoginCommand command)
    {
       **// duplication here**
        var user = from c in db.Users
            where c.EmailAddress = command.EmailAddress
            select c;

        user.LastLogin = DateTime.Now;
        ...
        db.Save();
   }
}

In both commands I retrieve the user based on his email-address. Now if I would like to trim the UI input before querying the database I would have to change this in two places.

I Could of course create a UserRepository which would e.g., have a method GetUserByEmailAddress and insert that IUserRepository into the constructor of my CommandHandlers. However, wouldn't this eventually create a "god repository" with Save, GetById, GetByUsername, etc?

And if I create a repository why create the separate Query objects?

How would one go about keeping this code DRY?

like image 708
user4419743 Avatar asked Feb 11 '23 05:02

user4419743


2 Answers

Why not refactor your Command Handler into one that implements multiple interfaces:

public class UserCommandHandler : CommandHandlerBase, 
                                  IHandle<ResetPasswordCommand>,
                                  IHandle<UpdateLastLoginCommand>
{
    public void Execute(ResetPasswordCommand command)
    {
        var user = GetUserByEmail(command.EmailAddress);

        user.EmailAddress = command.EmailAddress;
        ...
        db.Save();
   }

    public void Execute(UpdateLastLoginCommand command)
    {
        var user = GetUserByEmail(command.EmailAddress);

        user.LastLogin = DateTime.Now;
        ...
        db.Save();
   }

   private User GetUserByEmail(string email) {
            return (from c in db.Users
                   where c.EmailAddress = command.EmailAddress
                   select c).FirstOrDefault();
   }
}

This way, you can refactor private helper methods within the command handler, you command handler can handle similar commands, and you reduce your code duplication. You also won't need the "god" repository.

Personally, I'd rather have the private GetUserByEmail helper as a separate query class that I inject the db context in through the constructor, so that GetUserByEmail is a very specific class that gets me a User.

Hope this helps.

like image 64
David Hoerster Avatar answered Feb 13 '23 18:02

David Hoerster


It won't create a god repository . It will be a proper repository having a method used by a command use case. But this implies you're using the correct Repository Pattern, which means no IQueryable or EF exposed. Remember that a domain repository has 'query' methods needed only by the domain use cases and the repository only deals with domain aggregates roots (whole domain objects).

Your current approach is to use EF ( a DAO in the end) in your application services and this means the application layer and probably the domain layer as well are coupled to EF. Your high level services (a command handler is a service in the end, implementing a use case) shouldn't do queries because from their point of view there is no rdbms i.e they don't know about queries.

If your app is simple enough or you know it won't change much in the future, then you can take the shortcut of using directly EF, but if you decide to simplify things this way, then you don't need CQRS and a message based architecture.

like image 29
MikeSW Avatar answered Feb 13 '23 18:02

MikeSW