50

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?

Dave Schweisguth
  • 31,916
  • 10
  • 88
  • 112
Matthieu Napoli
  • 42,736
  • 37
  • 154
  • 239

2 Answers2

32

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.

Dave Schweisguth
  • 31,916
  • 10
  • 88
  • 112
  • 3
    `you can store a Command and execute it later` - This one made my day! Thanks!! – Cristian E. Apr 11 '15 at 10:49
  • 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? – m1lt0n Dec 16 '16 at 00:23
  • 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. – Dave Schweisguth Dec 17 '16 at 11:54
28

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));
      }     

   }

}
Alexander Derck
  • 11,742
  • 4
  • 43
  • 73
Mike
  • 2,375
  • 23
  • 34
  • 3
    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? – Matthieu Napoli Jun 30 '14 at 09:24
  • 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. :) – Mike Jun 30 '14 at 11:28
  • 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. – Robba Aug 23 '16 at 13:54
  • 2
    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.... – Mike Aug 23 '16 at 15:23
  • 2
    .... 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; } – Mike Aug 23 '16 at 15:25