Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DDD implementation

I'm new to Domain Driven Design and I have some doubt about some concepts (hoping that this is the right place to ask this).
I know that in DDD I should avoid an anemic model, so thinking about a social network model who should make (save) the friendship between two friends?
I imagine the situation like having a class representing the Users (using a Java-like syntax):

class User{
    String username
    List<User> friends
}

So, should it have a method to add a friend?

class User{
    void friendship(User friend)
}

or should I have to use a service to do it?

class UserService{
     void friendship(User user, User user2)
}
like image 656
rascio Avatar asked Apr 02 '13 23:04

rascio


2 Answers

My thought is that this is an example of what in relational database theory is termed a "weak entity". A Friendship could be identified solely by the identifiers of the two Users involved in the friendship, but could have its own properties such as when it was created and what type of relationship it is.

I would make this its own entity, and probably hide it behind a facade exposed by the User object:

class User {
    protected List<Friendship> _friendships { get; private set; }

    public IEnumerable<User> Friends {
        get { return _friendships.Select( /* get other user */ ); }
    }

    public void AddFriend(User otherUser) {
        // check to see if friendship exists
        // if not, create friendship
        // do other friendshippy things

        // make sure the other user knows about our friendship 
        // and gets to do its friendshippy things
        otherUser.AddFriend(this);
    }
}
like image 103
Matt Mills Avatar answered Sep 30 '22 15:09

Matt Mills


I would use something like

public sealed class Username : IEquatable<Username> { /* string wrap here */ }
public class User
{
    private readonly Username _username;
    private readonly HashSet<Username> _friends;
    public User(Username username)
    {
        if (null == username) throw new ArgumentNullException("username");
        _username = username;
        _friends = new HashSet<Username>();
    }

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

    public bool IsFriendsOf(User user)
    {
        if (null == user) throw new ArgumentNullException("user");
        return _friends.Contains(user.Name);
    }
}

Note that no collection is exposed by User, according to the Law Of Demeter. In case you'd really need them I would expose an IEnumerable<Username> for friends.

Moreover, in DDD, all query and commands should be part of the ubiquituous language (this is why I used Befriend instead of AddFriend).

However, let me say that this look a bit too CRUD to require a DDD. If you don't need (at least) a domain expert to understand the domain, you don't need DDD at all. If you don't need DDD, it becomes the most expensive error in your project.

edit
Let's suppose that the domain expert states that "friendship is always reciprocal" (as per guillaume31's suggestion): by modeling idempotent commands, you can ensure such a business rule very easily. The Befriend command becomes:

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

You can always model idempotent commands with such properties, but sometimes it requires a bit more of analysis to ensure that their arguments and their internal state provide everything they need.

like image 35
Giacomo Tesio Avatar answered Sep 30 '22 14:09

Giacomo Tesio