Reputation: 894
As a follow-on from a previous question of mine as I start a DDD journey, I have some reference data in an Invoicing context for item codes, which is managed in a Configuration context. A subset of the data is mirrored from Configuration to Invoicing (Id, Name) and I need to load this information for validating that an Item Code exists if someone is creating an Invoice.
Should I be modelling this Item Code reference data as an Aggregate Root in the Invoicing context? It seems a little 'overkill' to me as you would never update the Item Code inside the Invoicing context, but most guidance on DDD states that only Aggregates should be loaded from repositories.
I was thinking of declaring a 'lookup' repository which loads entities (as they have an ID, so wouldn't be a Value Object, I'd assume?), rather than a repository per set of reference data. Is this something that would be acceptable?
Upvotes: 1
Views: 1540
Reputation: 57387
I was thinking of declaring a 'lookup' repository which loads entities (as they have an ID, so wouldn't be a Value Object, I'd assume?), rather than a repository per set of reference data. Is this something that would be acceptable?
This is the right idea, but the spelling you are using isn't quite on point. The concept you are looking for is domain service, rather than repository.
I need to load this information for validating that an Item Code exists if someone is creating an Invoice.
If the authority for Item Code is somewhere else, and your Invoicing Model needs to know if a item code exists, then the usual pattern would be to have a domain service that you pass to the model. The domain service provides the capability to look up an item code, the domain model decides when that capability is needed.
// choose a spelling that is compatible with your naming conventions
// for domain services.
interface ItemCodes {
boolean exists(ItemCode itemCode);
}
// In your domain model, the use looks like
class InvoiceModel {
void createInvoice(..., ItemCodes itemCodes, ....) {
//...
if (! itemCodes.exist(code) ) {
...
}
}
}
The implementation details -- how you check that an item code exists -- are in an application service or an infrastructure service that implements the domain service contract.
For more on domain services, review chapter 5 of the blue book.
I had thought of creating an infrastructure service to do the checking but wanted to see if that was an acceptable approach. Would it be acceptable to have the data access logic inside this infrastructure service class, or should I still have a repository class handle that?
Part of the motivation for the different layers of abstraction is that we can hide the implementation details. Which means that we can change them freely. From your description of the problem, I would probably just use raw data access logic inside the infrastructure class, knowing that if we later discover it needs more repository like semantics we can change the implementation.
Upvotes: 1