Collections, relationships and tracking changes (in DDD)

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?

1

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.

If authors are Value Objects, you can easily re-create the whole list each time because only their value matters, you don’t have to relate them to identified objects. This might be at the cost of losing business intent though, since you don’t capture what the user precisely wants to do.

If they are Entities, I suggest sending granular commands to Book — AddAuthor, RemoveAuthor, ChangeAuthorOrder. The latter will have to include distinct order indexes for all authors, otherwise the Book can get in an inconsistent state.

0

The way I usually do this is based on a full update using a structured representation of the record. Some would call this a Data Transfer Object (DTO). Something like:

{ # book
  'id': 123,
  'title': 'The Art of Computer Programming',
  'authors': [
    {
       'id': 456,
       'name': 'Donald Knuth'
    }
  ]
}

In the list of authors, if the author record already exists, then it gets an id. If there’s no id, it’s a new record. Deleted authors simply do not appear in the list.

Depending on the application front-end, this is generated in different ways:

  • In a traditional HTML forms application, the server decodes the posted form data
  • In an Ajax application, JSON is generated on the client and sent to the server
  • Mobile and fat clients apps work somewhat like an Ajax app

I always use libraries so I don’t generate this by hand: the library generates it based on a structured definition of the form.

The next step is to validate the DTO, and apply it to your domain objects. There are some subtleties to doing it right. In particular, where an author already has an ID, you need to check the ID is already associated with that book. If not, you risk parameter tampering attacks.

Again, I always use libraries to do this. ToscaWidgets has great support for this, again doing all the validation based on a structured definition of the form.

The final step is to persist your domain objects. Most ORMs do this automatically.

This pattern lets your perform complex updates reliably. I’ve always like the style of large forms with sub-forms – rather than forcing users to click through multiple pages. I use this pattern a lot for highly complex forms, including multiple levels of nesting, and it works great.

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật