I have the following use case. I have an invoice which has lines and a contact. I am wondering whether logic related to checking if all information is there (i.e. at least one line, and the contact is present) should reside?
If the Invoice is your aggregate root than it should be the place for making sure that everything is correct. It makes of course sense to delegate validation to it's entities or value objects (lines, contact, etc.) for verifying their own data and invariants. But the aggregate is the logical boundary that makes sure your domain model does not enter an invalid state and will also orchestrate the logical flow if methods of it's children (entities and value objects) will need to be called.
That is also why you should not directly access child entities of an aggregate but only go through the API of the aggregate itself for performing business operations that manipulate state.
If the business logic you are referring to needs to work across several aggregate instances (i.e. it spans more than one Invoice) you should extract that logic into a domain service which is dedicated to cases where business logic is not constrained to a single aggregate instance.
I think the best place where you can put the logic is in the aggregate which is your invoice in that case. The aggregate takes care of the logic which is related to both the lines and contact. The contact shouldn't be coupled to the invoice and the lines shouldn't know about the invoice, since they are a list of entities on their own.
© 2022 - 2024 — McMap. All rights reserved.