8
votes

Mise en œuvre DDD

Je suis nouveau au design dirigé sur le domaine et j'ai un doute sur certains concepts (en espérant que c'est le bon endroit pour le demander).
Je sais que dans DDD, je devrais éviter un modèle anémique, alors pensez à un modèle de réseau social qui fort> devrait faire (sauvegarder) l'amitié entre deux amis?
J'imagine la situation comme ayant une classe représentant les utilisateurs (à l'aide d'une syntaxe de type Java):

class UserService{
     void friendship(User user, User user2)
}


2 commentaires

Votre classe est similaire avec une classe de nœuds à partir de la théorie des graphes. Voir Stackoverflow.com/questions/ 14764196 / ...


En fait, c'est juste un nœud :) et à cause de cela, j'utilise une base de données graphique, pour lier chaque entité ... La réponse à la question que vous me donnez est de stocker les identifiants, mais de cette manière Don Je perds des avantages d'utiliser un graphique db ??


7 Réponses :


6
votes

Ma pensée est que ceci est un exemple de ce que la théorie de la base de données relationnelle est appelée une "entité faible". Un amitié pourrait être identifié uniquement par les identifiants des deux Utilisateur S impliqué dans l'amitié, mais pourrait avoir ses propres propriétés telles que lors de sa création et quel type de relation C'est.

Je ferais cela sa propre entité et je la cache probablement derrière une façade exposée par l'utilisateur utilisateur xxx


7 commentaires

Je pensais également insérer une classe d'amitié pour stocker des informations (comme lorsque l'amitié a été créée, etc ...) mais dans la façon dont vous avez écrit, je devrais avoir un contrôleur qui ajoutez l'ami à l'aide de la classe d'utilisateurs, puis persistez ce changement Utilisation d'un USEREPOSITORY, alors pourquoi ne pas être préférable d'utiliser un service pour ajouter l'ami et persister le changement?


Principalement parce que la création de nouvelles entités est fondamentalement "logique de domaine". Ici, l'utilisateur sur lequel addfrienfien est appelé doit savoir sur l'autre utilisateur et par définition a tout de Les informations nécessaires à la création d'un nouveau amitié . Imaginez que ID utilisateur est protégé , par exemple (quelque chose que j'aime faire chaque fois que possible dans le DDD pour ces raisons) - Comment le service créerait-il le Amitié ?


mmmm oui, il a un sens ... mais si je définis l'utilisateur principal ID principal comme protégé, comment puis-je le récupérer? Si je créerais un lien dans une page Web sur le détail d'un utilisateur, et si l'identifiant principal n'est pas public, comment puis-je le faire? Utilisation du nom d'utilisateur comme ID de la classe dans l'application et juste l'ID principal (à partir d'une séquence par exemple) pour effectuer des opérations liées à la base de données? Dans ce cas, l'amitié est un agrégat, non?


que est où le service est disponible - vous pouvez obtenir une vision de l'utilisateur S - peut-être leur identifiant et son nom d'utilisateur, puis quand vous Besoin de faire quelque chose avec un utilisateur, vous pouvez le rechercher par ID et faire tout ce dont vous avez besoin avec celui-ci comme un utilisateur . C'est ainsi que vous restez à l'écart de la création du domaine anémique - si votre service ne sait rien sur les internes d'un utilisateur , il n'y a aucun moyen qu'il puisse faire ce qu'est un utilisateur est censé faire. A titre d'exemple - si vous me laissez passer un utilisateur et je ne peux pas regarder son identifiant, je ne peux pas faire partie de son interface avec Muck avec ses données dans la base de données.


Je pense qu'un service peut avoir un sens ici, mais cela dépend si vous traitez amitié en tant qu'entité dans un utilisateur agrégat ou comme agrégat séparé. Si c'est un agrégat séparé (peut-être avec deux entités qui pourrait également être des agrégats), un service est logique d'orchestrer l'amitié et l'insertion dans l'amitiéRepository. Les graphiques sont délicats dans DDD lorsque les nœuds et les bords ont à la fois une identité claire et des propriétés utiles.


Pour répondre à la question de savoir si un amitié est une racine globale - je ne le vois pas de cette façon. Un amitié , à mon avis, est explicitement défini comme une relation entre deux utilisateur S - il n'a pas d'identité de son propre extérieur de ce contexte.


L'amitié n'est-elle pas un objet de valeur?



5
votes

Je voudrais utiliser quelque chose comme xxx pré>

Notez qu'aucune collection n'est exposée par utilisateur, selon le loi de Demeter . Si vous auriez vraiment besoin d'eux, j'exposerais un iEnumerable code> pour amis. P>

De plus, dans ddd, tous La requête et les commandes doit faire partie du langage ubiquistueux (c'est pourquoi j'ai utilisé être ami code> au lieu de donfriend code>). p>

Cependant, laissez-moi dire que Ceci a l'air un peu trop crud pour exiger un DDD. Si vous n'avez pas besoin (au moins) un expert de domaine pour comprendre le domaine, vous n'avez pas besoin de DDD du tout strong>. Si vous n'avez pas besoin de DDD, il devient l'erreur la plus chère dans votre projet. P>

Modifier strong>

Supposons que l'expert du domaine indique que "l'amitié est toujours réciproque" (selon la suggestion Guillaume31 Strong>): en modélisant idempotent commandes, vous pouvez assurer une telle règle d'entreprise très facilement. La commande code> emprunt code> devient: p>

public void Befriend(User user)
{
    if (null == user) throw new ArgumentNullException("user");
    if(_friends.Add(user.Name))
    {
        user.Befriend(this);
    }
}


0 commentaires

2
votes

Ceci est similaire au problème Transferfunds () dans le domaine bancaire - Si vous appelez cette méthode sur le compte source ou le compte de destination? Et si un compte est capable de manipuler un autre compte 'S Balance en premier lieu?

Les services de domaine DDD sont utiles lorsque certains comportements ne semblent tout simplement pas conviennent à une entité existante ou manipulent plusieurs entités. Cela ne rend pas votre domaine anémique car le service est une partie la partie du domaine et qu'un nombre limité d'entités sans comportement ne signifie pas que tout votre modèle est anémique de toute façon.

Si la relation d'amitié est réciproque du début, il peut être plus logique de déléguer la création d'amitié à un service de domaine plutôt que d'avoir un utilisateur modifier un autre utilisateur Liste des amis.

Sinon, un donfrienfrienfrienfriend () méthode fonctionnera bien.


0 commentaires

2
votes

Un modèle de domaine faible ou anémique signifie simplement que vos "objets de domaine" sont des DTO, sans comportement. Ce que vous avez essentiellement obtenu est le modèle de script de transaction, dans lequel les DTO sont chargés, modifiés et enregistrés à nouveau. Crud, pour le dire d'une autre manière. C'est bien pour beaucoup d'applications, qui ne disposent pas de règles suffisamment complexes pour bénéficier d'une approche DDD.

Les objets de domaine doivent encapsuler comportement em>. C'est leur essence. Toute État publique (il est possible de ne pas avoir de getters ou de sigoteurs publics) devrait être réadonnée, et si vous souhaitez muter State, vous appelez une méthode liée à une affaire d'utilisation / entreprise. P>

Tous Votre «logique de domaine» doit être dans ces classes. La logique du domaine n'est qu'un nom de fantaisie pour décrire les règles et les paramètres de fonctionnement du domaine choisi. Soyez la banque, la vente au détail, les ressources humaines, etc. Lorsque les experts de votre domaine expliquent la case utilisateur "Pay par carte" et vous disent que "Nous ne pouvons pas ouvrir le peu avant que la machine PDC ait contacté la banque.", C'est une règle d'entreprise / invariant / pièce de logique de domaine. p>

Vous vous assemblerais normalement des objets de domaine (composés d'entités et d'objets de valeur) dans des agrégats, qui définissent une limite dans laquelle un ensemble de règles donné doit être satisfait. L'entité qui est la racine de ce graphique d'objet de domaine est connue sous le nom de racine d'agrégat et il s'agit uniquement d'agréger les racines que d'autres objets peuvent contenir des références. Dans votre cas, utilisateur code> est une entité et, comme il s'agit du seul objet de l'agrégat, il s'agit également de la racine globale. Donc, par exemple: P>

public class User // Entity and also the Aggregate Root 
{
    private readonly IList<Friendship> _friends = new List<Friendship>();

    public void Befriend(User user)
    {
        _friends.Add(new Friendship(/* Date? */, user));
    }

    public class Friendship // Entity
    {
        // ... Date?
        private User _friend { get; private set; }

        public Friendship(/* Date? */, User friend)
        {
            _friend = friend;
        }
    }
}


1 commentaires

MMMM Je ne pense pas que l'amitié est une racine d'agrégat ... elle n'a pas de comportement, il suffit de liens vers d'autres utilisateurs agrégats. Il ne devrait donc avoir que des liens mous pour les utilisateurs. Avec le concept d'événement Sourcing + CQRS, il s'agit d'un problème facile à résoudre, le utilisateur avoir un devenir ami (utilisateur) méthode qui ne modifie pas son état, mais le déclenche a AmitiéVent qui ont la Identity des deux utilisateurs, alors ces données peuvent être facilement stockées sur un DB graphique (pour la nature des informations, sinon peuvent être un SQL, ou un autre type de dB).



4
votes

Je pense; Une amitié est une racine agrégée elle-même. Il peut être directement créé dans un service d'application ou une création peut être délégué à un service de domaine.

Un service de domaine peut demander des agrégats d'utilisateurs pour la validation, si une validation spécifique à l'utilisateur nécessite. Ou expédiez les deux groupes d'utilisateurs au créateur / constructeur d'agrégats d'amitié.

Puis un reppositoy d'amitié peut facilement retourner une liste d'amis pour un utilisateur donné.

Même un agrégat d'amitié n'a pas de modèle ni de comportement riche; Il a une limite de consistance séparée.

En outre, si nous utilisons des événementsourcing; On peut écouter des événements d'amitié. et notifier aux deux utilisateurs de la situation.


0 commentaires

1
votes

L'amitié entre deux utilisateurs devrait être un agrégat séparé (AR). Comme un identifiant de celui que je recommande d'utiliser les identifiants des utilisateurs. De cette façon, vous avez un petit agrégat à basse pression que vous pourriez échouer / partitionner. Même chose pour les messages envoyés entre les utilisateurs. Chaque message est un agrégat.

Voici comment nous l'avons conçu et c'était un succès.

bonne chance


0 commentaires

0
votes

Considérant la quantité illimitée d'amitiés Un utilisateur peut avoir, je ne pense pas qu'il soit modélisé comme un objet de valeur dans l'utilisateur AR. Les AR devraient être aussi petits que possible et charger 10 km d'amis chaque fois que vous souhaitez modifier l'état n'est pas quelque chose d'idéal.

Je suis avec la possibilité d'avoir amitié et fricoRQUEST comme racines séparées. Un fricoRQuest est quelque chose qui vit dans une seule direction contenant un de_user_id et un to_user_id. Il peut être ignoré ou rejeté, ou accepté. Sur l'acceptation, une amitié à deux voies est établie. Les amitiés sont consultables par une vue matérialisée (par exemple ElasticseSearch), améliorées avec le nom d'utilisateur finalement mis à jour par les événements de mise à jour du profil utilisateur. Pour l'utilisateur UI au cas où un indicateur de bouton d'amitié conditionnel ou invité d'amitié est requis, il est nécessaire de conserver une table de liens / une vue de recherche avec les ID du amitié FriendQuest < / code>.


0 commentaires