What is the difference between Command + CommandHandler and Service?
Asked Answered
I

3

68

I have been reading about using Command objects to represent use cases that our domain exposes, and Command Handler objects to process those commands.

For example:

  • RegisterUserCommand
  • RegisterUserCommandHandler

But it looks exactly the same as having a RegisterUserService, where the command object would represent the parameters to the registerUser() method.

And of course, if the method had too many parameters, I would end up creating an object to wrap them and that object would be the same as the RegisterUserCommand.

So why have a different pattern to represent the same thing? Services are widespread, not Commands (from my experience); what is the difference here that I am missing? In short, why would I use one rather than the other?

Insphere answered 29/6, 2014 at 9:40 Comment(1)
Great question! I was wondering exactly the same issue.Frayne
P
44

Having Commands gives you the benefits of the good old Command pattern:

  • you can parameterize an object, e.g. a UI element, with a Command to perform
  • you can store a Command and execute it later, e.g. in a queue or a transaction log
  • you can track which Commands you executed, giving you a foundation for implementing undo

If your services were large, each with many complex methods (and if the methods weren't complex you probably shouldn't be using DDD or CQRS), then moving each method into a Command Handler might improve your application by making it more composable, easier to test, etc. No doubt it is common for people who refactor straight from big services to Commands/Command Handlers to regard this as a benefit of the latter pattern. But you could get the same benefit by decomposing large services into smaller ones (as suggested by the very specific service in your example), so strictly speaking that isn't a difference between services and Commands/Command Handlers.

Perspicacious answered 29/6, 2014 at 16:30 Comment(4)
you can store a Command and execute it later - This one made my day! Thanks!!Plexiglas
Regarding the benefits and commands being able to be stored, an adapter could convert commands to events if one wants to apply event sourcing, too, is this right Dave?Alexi
In the simplest case every Command would be an event that you want to persist and you would just persist all of your Commands and that would be event sourcing. Or you might only want to store some Commands as events but those Commands would still just be events. I can also imagine what you said, that every or some Command would produce events and not just be them, although I don't have a concrete example in mind.Perspicacious
If i understand correctly the question was about CommandHandlers and ApplicationServices.Chantress
P
39

I think you're completely right to question that these two concepts seem to be similar in context. It’s probably worth going back and considering, practically, what they are intended for.

DDD Services

In Domain Driven Design, there are different types of services e.g. Application Services (commonly UI services), Infrastructure Services and Domain Services.

Jimmy Bogard does an excellent job of explaining these

In a nutshell:

Domain Services

The job of the domain services is to execute functionality that typically doesn't suit for one entity. Consider using a domain service when you have a piece of functionality that requires a variety of
entities (aggregate / value objects). An example maybe: to calculate an estimate on how much a mortgage may cost, you require the detail on the buyer’s income / employment. You may require the buyer’s credit history and finally you may need information on the building that the mortgage is being consider for.

pricingService.CalculateMortageEstimate(BuyerIncomingDetails bid, BuyerCreditHistory bch, BuildingOverview bo)

Application Services

An example maybe services used as part of the UI.

Infrastructure Services

Services that tend to communicate with external resources (email senders, file systems, xml files, ftp etc...)

Command / CommandHandlers (CQRS)

Command Query Responsibility Segregation. As it says on the tin; a separation of:

  1. running queries against your data source
  2. Modifying (via commands) your data

using CQRS isn't always the right option but in my experience, people tend to use it when their data is distributed across multiple data sources.

So with the commands, you are explicitly asking for a unit of work (not to be confused with the UnitOfWork pattern) to be executed e.g. AddFraudRecordCommand or UpdateNoteCommand.


With that little refreshment on the differences between DDD services and CQRS commands. I would note the following things:

  1. Do I even need Command / CommandHandlers? What am I gaining, should I just go directly to the services?

  2. The job of my Command Handler is to handle the logic of my command (a Command being a very specific Request). Whereas the DDD services have different jobs (Domain Services: coordinate functionality of multiple entities, Infrastructure Services: collaborate with external services e.g. email)

  3. Maybe think of it like this: CommandHandler Job – execute the code to run the specific command (this may include using multiple services). Service Job – Depending on what type of service it is.

Not the best example, but I’m hoping it shines some light on what I’m trying to say:

public class CalculateFraudProbabilityCommandHandler : CommandHandler<CalculateFraudProbabilityCommand>
{
         IFraudService _fraudService;
         IEmailNotifier _notifier;
         ICustomerRepository _customerRepo;


  public CalculateFraudProbabilityCommandHandler(ICustomerRepository customerRepo, IFraudService fraudService, IEmailNotifier notifier) 
  {     
        _fraudService = fraudService; //Domain Service  
        _notifier = notifier;         //Infrastructure Service  
        _customerRepo = customerRepo; //Repository
  }

 //Execute Command
 public void Execute(CalculateFraudProbabilityCommand command) {

     Customer customer = _customerRepository.GetById(command.CustomerId);
     FraudHistory fraudHistory = _fraudService.RetrieveFraudHistory(customer);

     //any fraud recently? if so, let someone know!
      if(fraudHistory.FraudSince(DateTime.Now.AddYear(-1)) {
           _notifier.SendEmail(_fraudService.BuildFraudWarningEmail(customer,      fraudHistory));
      }     

   }

}
Plumbic answered 29/6, 2014 at 16:41 Comment(7)
Thank you for the detailed answer. I'm not sure I get your point though, I don't see where you explain the pro and cons between DDD services (domain of course) and commands?Insphere
I guess when I sat down to write this answer I was trying to explain what I consider the differences between using CommandHandler and Domain Services. With this in mind I didn't see it as a Handlers vs. Domain Services because they are used for different jobs. Admitally I've swayed from the question with a different point of view. :)Plumbic
If I may ask a (very) late question, doesn't the fraudService in your example violate the Single Responsibility Principle? On the one hand it seems to be responsible for retrieving fraud history details, but on the other hand, it's also responsible for building emails. I sometimes find it hard to find the balance between grouping related functionalities and strictly adhering to the SOLID principles.Fresno
Think of the CommandHandler as an 'orchestrator' of actions that need to occur to complete the task of executing the action. in the real world, CommandHandlers, tend to consist of a) find some additional data using the properties from the command and then b) action these. Having said that, in hindsight. the 'sending of the email' should be an Event off of the CalculateFraudProbabilityCommandHandler....Plumbic
.... so really the CalculateFraudProbabilityCommandHandler should of Raised and event e.g. RaiseEvent(FraudProbabilityCalculatedEvent) and there would be EventListeners that listen to this and run actions e.g. Send Emails. The FraudProbabilityCalculatedEvent object may have a property on it called public bool FraudFound { get; set; }Plumbic
Maybe a CommandHandler is just a specialized Domain ServiceLouiselouisette
@Plumbic If the handler uses uow, should the services be injected in uow or the handler itself?Vivie
D
0

Queries and commands are data transfer objects, (as another post said, you can store them). Typically you would create a command handler or a query handler. For each handler you have a specific command or query required that corresponds to the data it needs to perform the action. Command and query handlers are just services arround one specific use case in particular. We could call them use cases directly but because of CQRS we divide the system into 2 separates part for writing/modifications, the command handlers, and for request without any side effects, the query handlers.

Deluna answered 25/3 at 12:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.