I am currently developing some reasonably large applications for a client in the travel industry using .net and nhibernate, and am coming up against a few issues with implementing DDD, and disagreements within the team on the best way to proceed. I'm hoping someone can offer some guidance.
At the moment, we have implemented a service layer outside of the domain, with a service per aggregate root ([EntityName]Service). All other layers use these services get references to an aggregate root via methods like GetByThis() and GetByTheOther(). All our calls into the domain from other layers are via these services.
The services hold injected references to repositories (which are referenced nowhere else) and are also responsible for all save/update behaviour and managing transactionality. The service methods are growing in complexity, and sometimes have behaviour which seems to belong to the domain, like conditional creation logic (if property = this set child objects to something, otherwise something else). Our domain entities have mostly simple methods like GetByThis() and HasAThing(). I feel that we are losing the expressiveness of our domain.
My main issues are:
- Should the service layer contain so much logic? if not where should it go? if the domain, should aggregate roots hold references to repositories? if yes, how are these to be injected (into factories that create aggregate roots?)
- How should transactionality be handled?
- Should entities (or aggregate roots) hold references to domain services? If so, how should they obtain the references?
- In order to get a new id for an entity, we must call a stored procedure, which we have wrapped in a repository. Where would you reference this? Some complex methods on Entities which need to create many child entities would need to reference this?
EDIT
Thanks for the well thought answers @david-masters and @guillaume31.
You have helped me resolve that ‘smelly code’ feeling that I was getting.
Firstly, I should have said that we have a (very) legacy oracle DB to contend with, hence the Id Generation requirement (amongst other issues).
For anyone else who looks at this, both answers gave excellent advice, but for me, this was the best advice:
“From a pragmatic perspective, here's what I would ask myself : if I want to take a part of my Domain layer and reuse it in another application, will it contain all the business rules and behaviour I need to leverage the domain in that new application ? If not, then maybe it means some parts that are currently on the application side need to be moved to the domain layer.”
I reassessed our domain and service layer with this in mind, and now believe I have resolved our design issues