J'ai lu sur l'utilisation d'objets Command pour représenter des cas d'utilisation que notre domaine expose et des objets Gestionnaire de commandes pour traiter ces commandes.
Par exemple:
RegisterUserCommand
RegisterUserCommandHandler
Mais cela ressemble exactement à un RegisterUserService
, où l'objet de commande représenterait les paramètres de la méthode registerUser()
.
Et bien sûr, si la méthode avait trop de paramètres, je finirais par créer un objet pour les envelopper et cet objet serait le même que le RegisterUserCommand
.
Alors pourquoi avoir un motif différent pour représenter la même chose? Les services sont répandus, pas les commandes (d'après mon expérience); quelle est la différence ici qui me manque? En bref, pourquoi devrais-je utiliser l'un plutôt que l'autre?
Avoir des commandes vous donne les avantages du bon vieux modèle de commande:
Si vos services étaient volumineux, chacun avec de nombreuses méthodes complexes (et si les méthodes n'étaient pas complexes, vous ne devriez probablement pas utiliser DDD ou CQRS), le déplacement de chaque méthode dans un gestionnaire de commandes pourrait améliorer votre application en la rendant plus composable, plus facile à tester, etc. Sans aucun doute, il est courant pour les personnes qui refactorisent directement des gros services aux gestionnaires de commandes/commandes de considérer cela comme un avantage de ce dernier modèle. Mais vous pourriez obtenir le même avantage en décomposant les grands services en plus petits (comme suggéré par le service très spécifique dans votre exemple), donc à proprement parler ce n'est pas une différence entre les services et les commandes/gestionnaires de commandes.
Je pense que vous avez tout à fait raison de remettre en question le fait que ces deux concepts semblent similaires dans leur contexte. Cela vaut probablement la peine de revenir en arrière et de considérer, pratiquement, à quoi ils sont destinés.
Dans Domain Driven Design, il existe différents types de services, par exemple Services d'application (généralement les services d'interface utilisateur), services d'infrastructure et services de domaine.
Jimmy Bogard fait un excellent travail pour les expliquer
En un mot:
Services de domaine
Le travail des services de domaine consiste à exécuter des fonctionnalités qui ne conviennent généralement pas à une entité. Envisagez d'utiliser un service de domaine lorsque vous disposez d'un élément de fonctionnalité qui nécessite une variété de
entités (objets agrégés/valeur). Un exemple peut-être: pour calculer une estimation du coût d'une hypothèque, vous avez besoin des détails sur le revenu/l'emploi de l'acheteur. Vous pouvez avoir besoin des antécédents de crédit de l'acheteur et, enfin, vous pourriez avoir besoin d'informations sur le bâtiment pour lequel l'hypothèque est envisagée.
pricingService.CalculateMortageEstimate(BuyerIncomingDetails bid, BuyerCreditHistory bch, BuildingOverview bo)
Services d'application
Un exemple peut être des services utilisés dans le cadre de l'interface utilisateur.
Services d'infrastructure
Services qui ont tendance à communiquer avec des ressources externes (expéditeurs d'emails, systèmes de fichiers, fichiers xml, ftp etc ...)
Ségrégation de responsabilité de requête de commande. Comme il est dit sur l'étain; une séparation de:
utiliser CQRS n'est pas toujours la bonne option, mais d'après mon expérience, les gens ont tendance à l'utiliser lorsque leurs données sont réparties sur plusieurs sources de données.
Ainsi, avec les commandes, vous demandez explicitement qu'une unité de travail (à ne pas confondre avec le modèle UnitOfWork) soit exécutée, par ex. AddFraudRecordCommand ou UpdateNoteCommand.
Avec ce petit rafraîchissement sur les différences entre les services DDD et les commandes CQRS. Je voudrais noter les choses suivantes:
Ai-je même besoin de Command/CommandHandlers? Qu'est-ce que je gagne, dois-je aller directement aux services?
Le travail de mon gestionnaire de commandes est de gérer la logique de ma commande (une commande étant une demande très spécifique). Alors que les services DDD ont des tâches différentes (Services de domaine: coordonner les fonctionnalités de plusieurs entités, Services d'infrastructure: collaborer avec des services externes, par exemple la messagerie électronique)
Pensez-y peut-être comme ceci: CommandHandler Job - exécutez le code pour exécuter la commande spécifique (cela peut inclure l'utilisation de plusieurs services). Travail de service - Selon le type de service dont il s'agit.
Pas le meilleur exemple, mais j'espère que cela éclaire ce que j'essaie de dire:
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));
}
}
}