Architecture – Collections, relationships and tracking changes (in DDD)

Architecture

Let's say we have a Book that has a List of Authors. Order of Authors is important.

We then have the update page, where user can 1) add new author, 2) remove existing author or 3) change the order. What I have as the input is the list of new authors.

I find this problem often – there is often a lot of models with this kind of relationship. Sometimes the order is not important (so we use Set) but more-less is like this.

In my business method, I need to:

  • detect new Authors, so I can insert them
  • detect removed Authors, so I can remove them
  • assume everything else is updated.

I can not simply reapply authors (delete and then insert) since there is additional data related to a book and author.

Doing this manually every time is error-prone. Is there a better way to track changes in related collections?

Should I track changes on UI instead (as this is where they happens) and then provide more input then just one list of all users: for example, list of changes, list of removals? In that case my business method would take more parameters, i.e. lists for each type of change (removal, etc).

Finally, I was thinking into storing set of events per update, so I can repeat them on model easily.

Should I handle this margining in model or in my service method?

Any wisdom on this?

Best Answer

I will try to answer with the info you gave me.

You wrote

I need to:

  • detect new Authors, so I can insert them
  • detect removed Authors, so I can remove them
  • assume everything else is updated.

So I think that your approach is too CRUD for DDD and aggregate roots. My 2 cents your business method is something like Update(Book) and the parameter is the modified Book (its data, isbn or title for example, and/or its author collection) and that is why you have to "detect" changes in the aggregate root and why you are in trouble about how to do that.

I would implement a command pattern and segregate every user-case into a command.

  1. Edit book info
  2. Add author
  3. Remove author
  4. Edit author
  5. Change author order

This will need a good task-based UI design.

Then, you can choose the most suitable strategy:

  1. Execute every command instantly and save into persistence. Get Book aggregate root, modify book data or author collection (depends of the command) and update persistence. No need of tracking changes.

  2. Execute every command instantly in the aggregate root in memory and wait user push "Save" button. Then go to persistence. If you store the commands executed in the aggregate until persistence is updated you already know what update in persistence. Changes tracked by the commands executed in the aggregate.

  3. Store a list of generated commands by the user and execute it in a batch when user push "Save"; use (1) or (2) strategy to update aggregate and persistence.

Last words and tips:

Even UI design affects the architecture and patterns you can use. Think in everything as a whole.

Every strategy listed above has its uses. Depends of your domain, context, environment, technologies you use, etc.

You can use several strategies. No need to stick just in one in every bounded context.

Your domain has to model user-case actions. Don't do just Update(Book). Model every action (every command execution) in its own function and apply its relevant domain rules and invariants.

Related Topic