So I have been reading about DDD for some time and trying to figure out the best approach on several issues.
I tend to agree that I should design my model in a persistent agnostic manner. And that repositories should load and persist my models in valid states.
But are these approaches realistic practically? I mean its normal for a model to hold a reference to a collection of another type. Persisting that model should mean persist the entire collection. Fine. But do I really need to load the entire collection every time I load the model? Probably not.
So I can have specialized repositories. Some that load maybe a subset of the object graph via DTOs and others that load the entire object graph. But when do I use which? If I have DTOs, what’s stopping client code from directly calling them and completely bypassing the model?
I can have mappers and factories to create my models from DTOs maybe? But depending on the design of my models that might not always work. Or it might not allow my models to be created in a valid state.
EDIT 1:
Aside from lazy/eager loading and using a DI framework to inject repositories in my models, what is another approach?
What’s the correct approach here?
First is that, it is hard to have both complex model and good performance. This is compromise you need to make. To have both, you would need much bigger investment than sum of both. If you really need performance, DDD is not good alternative.
Second is, that you are worrying about performance before actually writing code and profiling it. Maybe the performance implications are not that bad as you think and you can easily use object-access/ORM/lazy approach without troubles.
But if you find out, through profiling, that performance is bad, maybe because you are hitting DB too often. Solution is probably just like you said: specialized methods on repositories. Those can either return entity along with some related entities already required (eager loading through ORM) or by doing a queries, that return specific aggregate or filtered data. Also, there seems to be some confusion, those repository methods and objects they return are part of the model, just like repositories they belong to. So “bypassing model” doesn’t make sense here. You just need to continuously keep eye on performance and make sure developers use the correct methods to reduce code duplication and leverage the more efficient methods.
2