C# – DDD: Identifying aggregate root in a simple example application domain

aggregateArchitecturecdomain-driven-designobject-oriented

I'm trying to read about DDD, and i'm struggling a bit trying to to identify aggregate roots. I wrote a really simple app to divide players into different teams inside a game.

So my entities are something like this:

Game Entity:

public class Game : DomainEntityBase, IDomainEntity
{
    private List<Team> teams = new List<Team>();

    private List<Player> players = new List<Player>();

    private int teamSize;

    public Game(
        string gameName,
        int teamSize,
        IEnumerable<Player> players) : base(Guid.NewGuid())
    {
        this.teamSize = teamSize;

        this.players = players.ToList();
    }

    public string GameName { get; private set; }

    public ReadOnlyCollection<Team> Teams => teams.AsReadOnly();

    public void SplitPlayersToTeams()
    {
        if (players.Count() % 2 != 0)
        {
            throw new NotSupportedException("Only equally dividable teams are supported");
        }

        var teamCount = players.Count / teamSize;

        var playersPerTeam = players.Count / teamCount;

        SetPlayersToTeam(teamCount, playersPerTeam);
    }

    private void SetPlayersToTeam(int teamCount, int playersPerTeam)
    {
        var rnd = new Random();

        for (var i = 0; i < teamCount; i++)
        {
            var team = new Team(i.ToString());

            while (team.Players.Count != playersPerTeam)
            {
                var randomIndex = rnd.Next(players.Count);

                var player = players[randomIndex];

                if (!team.Players.Contains(player))
                {
                    player.SetTeam(team);
                    team.AddPlayer(player);
                }
            }

            teams.Add(team);
        }
    }
}

Team Entity:

public class Team : DomainEntityBase, IDomainEntity
{
    private List<Player> players = new List<Player>();

    public Team(
        string teamIdentifier) : base(Guid.NewGuid())
    {
        TeamIdentifier = teamIdentifier;
    }

    public string TeamIdentifier { get; }

    public ReadOnlyCollection<Player> Players => players.AsReadOnly();

    public void AddPlayer(Player player)
    {
        players.Add(player);
    }
}

Player entity:

public class Player : DomainEntityBase, IDomainEntity
{
    public Player(
        string nickName) : base(Guid.NewGuid())
    {
        Nickname = nickName;
    }

    public string Nickname { get; private set; }

    public Team Team { get; private set; }

    public void SetTeam(Team team)
    {
        Team = team;
    }
}

Now first I was thinking that the game would be an aggregate root. It would make sense in a way. But then I started thinking that what if you want to persist players separately so that you don't have to add new players for every game? What if you want to persist teams separately if you have teams that can be re-used later? The game it self, would be aggregate root, because I would persist games to for example load a history of games from persistence.

So the question is, is every object I listed above an aggregate root, having their own repositories since every aggregate root should have it's own repository?

Thanks in advance.

Best Answer

Decision that what should be selected as an aggregate root is highly dependent on business rules of your application . If for example , there are two entities say A and B are highly dependent i.e. some operations on entity B requires change in entitiy A then A and B should be under same aggregate root . In short if consistency is needed between two entities than they can have same aggregate root .

In Your case it is also dependent on business rules that what should be selected as an aggregate .

If Considering following Business Rules :

Business Rules Assumptions 1

  1. In the Game , Team is made at runtime and there is not existence of team after game is over .
  2. In the Game , Players are also created in runtime for any User in your system and player also have no existence after game is over
  3. We can consider example of online LUDO game here where players and teams are created at runtime .

Now Considering above rules , It seems that Player and Teams are highly correlated/coupled that Only Game aggregate Root is OK here .

If Considering following Business Rules :

Business Rules Assumptions 2

  1. Teams can exists independently of GAME , which is the more real scenario .
  2. Players also exists independently .
  3. Players can be assigned to different Teams .
  4. Team can play different Games .

Now Considering above rules , it seems that Game, Player and Team should exists as seperate aggregate roots .

One Different approach for deciding aggregates can be event storming , where you first write single source of truth i.e. the things which has happened for example :

  1. GameStarted
  2. TeamCreated
  3. PlayerAddedToTeam and so on.

On defining these events , Business will also become more clear to you .

Now write what Command can cause these events and keep on writing the flow .

After some time it will become clear that what commands and events should come from a single point and that can be selected as an aggregate .

But please note that after this also you need to cross check with business rules if you further need to break aggregate or not .

Hope this will clear some doubts .

Please comment if have some doubt in answer .

Thanx in advance .