0

I will describe the problem in a typical example Todo Application.

The user can have many TodoList. A TodoList could have many Todo.

The use case is "Add Todo to the TodoList".

In this case, with my basic knowledge, I think the TodoList must have an add method to add the todo to itself.

Since the Todo details like content, description, dueDate, complete could be persisted independently from the TodoList, the Todo must be another Aggregate Root. Also, the TodoList doesn't care about the Todo details, but only its id.

Because of all the above statements, I think this is the process of the add Todo process:

Create Todo -> Persist the Todo to the database -> Add Todo to the TodoList by Id -> Persist the relation to the database

I don't know if this is the best practice or the right thing to do, so I want to ask you guys your opinion about this. If you have a better solution, please share.

4
  • 1
    "could be persisted independently with the TodoList" - did you mean "could be persisted independently from the TodoList"? If that's the case, then why? I guess a typical "todo list" application could load a whole list into memory, lets the user edit the list, and save it back as a whole. Or do you mean you choose to design your application in a way it lets the user load, edit and save "todo" items which don't belong to a specific list?
    – Doc Brown
    Dec 22 '21 at 6:42
  • Wow. Your comment really shows me the light, @DocBrown. So like the Microsoft Todo, they persist the whole to-do list at once? When I change a to-do description, it persists the whole list for it? Dec 22 '21 at 7:38
  • Well, I don't know "Microsoft todo", but both design approaches are definitely possible, and I am sure there exist both kind of applications, some dealing with "tasks" or "todo"' as individual aggregates, and others which manage the list always as a whole.
    – Doc Brown
    Dec 22 '21 at 8:01
  • Relational databases make persistence of aggregates a lot harder than it needs to be. Using a document database might prove to be a lot simpler for your todo list. Wait until you have a collection of value objects; how are you going to store that in a relational database?
    – Rik D
    Dec 22 '21 at 20:24
2

The process of adding items to a list which is persisted in a (lets say, relational) database is technically not different whether you use DDD or any other kind of methodology. At the end, it will always boil down to these technical steps:

  1. Create list item record ("Todo")
  2. Put the list's ID into the related item's foreign key field
  3. Insert the item into the DB ("persist it")

If those steps happen for a system where "Todo" is an aggregate (and root) on its own, or for a "Todo list" with all items together forming the aggregate is not a huge difference, except for where one puts the transaction boundaries.

3
  • You are right. The key difference is where to put the transaction boundaries. But somehow I find it hard to define the transaction boundaries. In this case, the Todo does not make sense without being in a Todo List, but the Todo itself could be persisted independently with its own properties. Are there any tips to define these transaction boundaries? Dec 22 '21 at 9:51
  • 1
    @NgọcNguyễn: choosing these boundaries is part of what the design aspect of softwareengineering takes. There are rough guidelines, of course. When a todolist has the form of a reasonable sized document, and the idea is to always be edited by a single user, and save performance is not an issue, one may choose to persist it always "as a whole". If one wants to let multiple users edit different items simultanously, or the list or the items are really huge, so you want to save them in smaller portions for safety reasons, then go for smaller aggregates / transactions...
    – Doc Brown
    Dec 22 '21 at 10:18
  • 1
    .. but in the end, it comes down to your design experience, your requirements and sometimes to your taste.
    – Doc Brown
    Dec 22 '21 at 10:19
3

If you're aiming for domain-driven design, then it doesn't matter if the Todo is persisted with or independently of the TodoList. Persistence isn't part of the domain.

Can a Todo exist if it's not on a TodoList? Does a TodoList have more information than just the collection of Todo, such as a name or description? Yes? Your TodoList just became more than just a collection.

A good example I saw once was a team of players. If you just throw some code at it, you might think a team is just a collection of players, but it's really more. A team has a name, a win-to-loss ratio, a mascot, an owner, a coach, a home city... The "collection of players" is just one property of a team. And sure, a team will draft new players or trade players. Once you start thinking a bit more about the domain (instead of just the code), you start seeing these domain verbs that, then, describe your model.

class Team {
   Person Coach {get;}
   string Mascot {get;}
   IEnumerable<Person> Roster {get;}

   void DraftPlayer (Person newPlayer);
   void TradePlayer (Person playerBeingTraded, Team toTeam);
   void FirePlayer (Person playerBeingFired);
}

If the true domain verb for "adding a Todo to a TodoList" really is "add", then it's just coincidence that it happens to be the same reserved word that your collection uses in code. What's more important is that you're using verbs that apply to the domain instead of keywords reserved by your programming language.

2
  • You are right that persistence is not part of the domain, but in the DDD book, the Aggregate is defined to be seen as a unit that has to be persisted together, that's why I mention persistence. Let's use your example of a team of players. The player could have some properties like height, weight, status, etc., and those properties could be updated. How could you update those properties? Through the Team Aggregate or the Player Aggregate? Dec 22 '21 at 8:18
  • @NgọcNguyễn, "persisted together" means that the parts of an Aggregate are persisted at the same time, in the same transaction. But an aggregate can span multiple tables in the database. If you want to update some property of a Player (for example, a player has lost some weight), then you would use the Team Aggregate to retrieve the correct Player object and modify the properties of that Player. When all modifications are done, you tell the Team Aggregate to update its persisted state. Dec 22 '21 at 13:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.