web-dev-qa-db-fra.com

Services de domaine vs. Factions vs. Racines d'agrégats

Après avoir géré le DDD pendant des mois maintenant, je suis toujours confondu à propos des objectifs généraux des services de domaine, des usines et des racines agrégées en relation les unes des autres, par exemple. où ils se chevauchent dans leur responsabilité.

Exemple: J'ai besoin de 1) créer une entité de domaine complexe dans une saga (gestionnaire de processus) suivie de 2) Un certain événement de domaine qui doit être manipulé ailleurs alors que 3) L'entité est clairement une racine globale qui marque un contexte délimité à d'autres entités.

  1. L'usine IS être responsable de la création de l'entité/racine agrégée
  2. Le service peut créer l'entité, car il jette également l'événement de domaine
  3. Le service peut agir comme une racine globale (créer une "sous-traitance" de "entité" avec ID 4)
  4. La racine globale peut créer et gérer des "sous-traities"

Lorsque j'introduit le concept de racine globale ainsi qu'une usine à mon domaine, un service ne semble plus nécessaire. Cependant, si je ne le suis pas, le service peut gérer tout ce dont il a besoin avec les connaissances et les dépendances qu'il a.

exemple de code en fonction du langage omniprésent d'une boutique de réparation de voiture

public class Car : AggregateRoot {

    private readonly IWheelRepository _wheels;
    private readonly IMessageBus _messageBus;

    public void AddWheel(Wheel wheel) {
        _wheels.Add(wheel);
        _messageBus.Raise(new WheelAddedEvent());
    }

}

public static class CarFactory {

    public static Car CreateCar(string model, int amountofWheels);

}

.. ou ...

public class Car {

    public ICollection<Wheel> Wheels { get; set; }

}

public interface ICarService {

    Car CreateCar(args);
    void DeleteCar(args);
    Car AddWheel(int carId, Wheel wheel);

}
6
Acrotygma

DDD est en partie une réaction à des modèles de domaine anémiques, où vos entités n'auraient qu'un état, mais pas un comportement.

C'est vrai que dans un sens, vous pouvez mettre tout le comportement de la voiture dans un service séparé, mais pourquoi voudriez-vous? Pour que cela fonctionne, vous auriez besoin d'exposer toutes sortes d'état dans la voiture, que vous aimeriez normalement garder privée (comme des roues).
[.____] Si vous exposez des roues comme celle-là, tout code pourrait faire toutes sortes de choses géniales à cette collection, en dehors de tout flux d'affaires normal. N'oubliez pas que le point d'un agrégat consiste à avoir quelque chose qui est transactionnellement cohérent entre les transactions de flux d'entreprise. Exposer des roues comme ça compromettait complètement cette sécurité.
[.____] Par exemple: Dites que votre entreprise ne veut que soutenir les voitures avec quatre roues. Si vous encapsulez l'accès aux roues, vous pouvez appliquer cela. Si vous ne le faites pas, il est complètement possible d'ajouter cent roues à une voiture, car les roues seraient exposées.

Un service est généralement utilisé comme coordinateur. Un commandhandler (en supposant quelque chose comme CQRS) traduit un objet de commande à des paramètres plus fortement dactylographiés, réduisant ainsi l'obsession primitive. Ensuite, il peut appeler un service avec ces paramètres plus "domaines-ish". Le service récupère des entités de référentiels et invoque les comportements sur eux. Selon votre architecture, vous pouvez ensuite collecter des modifications (événements) et les transmettre à un bus ou autre.
[.

Quant à une usine (comme de côté), rien ne vous empêche d'ajouter une méthode d'usine statique de votre classe d'agrégats, au lieu de créer une usine séparée.

6
Stefan Billiet

Après avoir géré le DDD pendant des mois maintenant, je suis toujours confondu à propos des objectifs généraux des services de domaine, des usines et des racines agrégées en relation les unes des autres, par exemple. où ils se chevauchent dans leur responsabilité.

La racine globale est chargée de veiller à ce que l'État soit conforme à l'invariant d'entreprise. Dans CQRS LINGO, vous modifiez le modèle en émettant des commandes à une racine globale.

Le service de domaine est un mécanisme de support requis pour les agrégats. Par exemple, un service de domaine peut prendre en charge un calcul. Le gestionnaire de commande transmet le service de domaine à l'agrégat, l'agrégat (traitement d'une commande) nécessite le résultat du calcul, de sorte qu'il passera au service de domaine les parties de son état qui sont nécessaires en tant qu'entrées dans le calcul. Le service de domaine effectue le calcul et renvoie le résultat, et l'agrégat peut alors décider quoi faire avec le résultat.

"Usine" peut signifier deux choses. Si vous utilisez l'usine pour créer une entité située dans la limite d'agrégat, il s'agit simplement d'un détail de mise en œuvre - vous pouvez l'utiliser si la construction de l'objet est compliquée.

Dans certaines circonstances, le terme "référentiel" est utilisé. Cela implique généralement qu'il fait partie de la couche de persistance (ne partie du modèle de domaine) responsable de la création de racines agrégées. À peu près, le gestionnaire de commande (qui fait partie de l'application) valide une commande, puis utilise le référentiel pour charger la racine d'agrégat à laquelle la commande est adressée à. Le gestionnaire de commandes d'invoquera ensuite la méthode spécifiée sur la racine d'agrégat, passant des paramètres de l'objet de commande et éventuellement passer dans le service de domaine comme un argument.

Dans vos exemples, la question clé à poser est la responsabilité de décider si une commande devrait être exécutée de la vie. L'application est chargée de s'assurer que la commande est bien formée (toutes les données de commande sont présentes, les données ont été traduites en valeurs reconnues par le domaine sans lancer des erreurs de validation, etc.). Mais qui doit décider "Non, vous ne pouvez pas ajouter une roue en ce moment - les règles de l'entreprise ne le permettent pas!"

Dans le monde DDD, c'est incontestablement la responsabilité de la racine globale. Donc, toute logique pour déterminer cela devrait être dans la racine globale et la icarservice s'en va.

(La mise en œuvre alternative, où l'agrégat expose son état et que le service de voitures vérifie les règles de l'entreprise et manipule l'état de l'objet, est considéré comme un exemple d'agrégat "anémique". "Setteurs" dans un L'agrégat est une odeur de code. "getters" dans un agrégat est souvent une odeur de code - en particulier dans les CQRS, où la responsabilité de requêtes de soutien est supposée être "ailleurs" - dans le modèle de lecture.)

6
VoiceOfUnreason