In Domain Driven Design, there seems to be lots of agreement that Entities should not access Repositories directly.
Did this come from Eric Evans Domain Driven Design book, or did it come from elsewhere?
Where are there some good explanations for the reasoning behind it?
edit: To clarify: I'm not talking about the classic OO practice of separating data access off into a separate layer from the business logic - I'm talking about the specific arrangement whereby in DDD, Entities are not supposed to talk to the data access layer at all (i.e. they are not supposed to hold references to Repository objects)
update: I gave the bounty to BacceSR because his answer seemed closest, but I'm still pretty in the dark about this. If its such an important principle, there should be some good articles about it online somewhere, surely?
update: March 2013, the upvotes on the question imply there's a lot of interest in this, and even though there's been lots of answers, I still think there's room for more if people have ideas about this.
I learnt to code object oriented programming before all this separate layer buzz appear, and my first objects / classes DID map directly to the database.
Eventually, I added an intermediate layer because I had to migrate to another database server. I have seen / heard about the same scenario several times.
I think separating the data access (a.k.a. "Repository") from your business logic, is one of those things, that have been reinvented several times, altought the Domain Driven Design book, make it a lot of "noise".
I currently use 3 layers (GUI, Logic, Data Access), like many developer does, because its a good technique.
Separating the data, into a
Repository
layer (a.k.a.Data Access
layer), may be seen like a good programming technique, not just a rule, to follow.Like many methodologies, you may want to start, by NOT implemented, and eventually, update your program, once you understand them.
Quote: The Iliad wasn't totally invented by Homer, Carmina Burana wasn't totally invented by Carl Orff, and in both cases, the person who put others work, all togheter, got the credit ;-)
To cite Carolina Lilientahl, "Patterns should prevent cycles" https://www.youtube.com/watch?v=eJjadzMRQAk, where she refers to cyclic dependencies between classes. In case of repositories inside aggregates, there is a temptation to create cyclic dependencies out of conveniance of object navigation as the only reason. The pattern mentioned above by prograhammer, that was recommended by Vernon Vaughn, where other aggregates are referenced by ids instead of root instances, (is there a name for this pattern?) suggests an alternative that might guide into other solutions.
Example of cyclic dependency between classes (confession):
(Time0): Two classes, Sample and Well, refer to each other (cyclic dependency). Well refers to Sample, and Sample refers back to Well, out of convenience (sometimes looping samples, sometimes looping all wells in a plate). I couldn't imagine cases where Sample would not reference back to the Well where it's placed.
(Time1): A year later, many use cases are implemented .... and there are now cases where Sample should not reference back to the Well it's placed in. There are temporary plates within a working step. Here a well refers to a sample, which in turn refers to a well on another plate. Because of this, weird behaviour sometimes occurs when somebody tries to implement new features. Takes time to penetrate.
I also was helped by this article mentioned above about negative aspects of lazy loading.
In the ideal world , DDD proposes that Entities should not have reference to data layers. but we do not live in ideal world. Domains may need to refer to other domain objects for business logic with whom they might not have a dependency. It is logical for entities to refer to repository layer for read only purpose, to fetch the values.
I found this blog to have quite good arguments against encapsulating Repositories inside Entities:
http://thinkbeforecoding.com/post/2009/03/04/How-not-to-inject-services-in-entities
What an excellent question. I am on the same path of discovery, and most answers throughout the internet seem to bring as many problems as they bring solutions.
So (at the risk of writing something that I disagree with a year from now) here are my discoveries so far.
First of all, we like a rich domain model, which gives us high discoverability (of what we can do with an aggregate) and readability (expressive method calls).
We want to achieve this without injecting any services into an entity's constructor, because:
How, then, can we do this? My conclusion so far is that method dependencies and double dispatch provide a decent solution.
CreateCreditNote()
now requires a service that is responsible for creating credit notes. It uses double dispatch, fully offloading the work to the responsible service, while maintaining discoverability from theInvoice
entity.SetStatus()
now has a simple dependency on a logger, which obviously will perform part of the work.For the latter, to make things easier on the client code, we might instead log through an
IInvoiceService
. After all, invoice logging seems pretty intrinsic to an invoice. Such a singleIInvoiceService
helps avoid the need for all sorts of mini-services for various operations. The downside is that it becomes obscure what exactly that service will do. It might even start to look like double dispatch, while most of the work is really still done inSetStatus()
itself.We could still name the parameter 'logger', in hopes of revealing our intent. Seems a bit weak, though.
Instead, I would opt to ask for an
IInvoiceLogger
(as we already do in the code sample) and haveIInvoiceService
implement that interface. The client code can simply use its singleIInvoiceService
for allInvoice
methods that ask for any such a very particular, invoice-intrinsic 'mini-service', while the method signatures still make abundantly clear what they are asking for.I notice that I have not addressed repositories exlicitly. Well, the logger is or uses a repository, but let me also provide a more explicit example. We can use the same approach, if the repository is needed in just a method or two.
In fact, this provides an alternative to the ever-troublesome lazy loads.
Update: I have left the text below for historical purposes, but I suggest steering clear of lazy loads 100%.
For true, property-based lazy loads, I do currently use constructor injection, but in a persistence-ignorant way.
On the one hand, a repository that loads an
Invoice
from the database can have free access to a function that will load the corresponding credit notes, and inject that function into theInvoice
.On the other hand, code that creates an actual new
Invoice
will merely pass a function that returns an empty list:(A custom
ILazy<out T>
could rid us of the ugly cast toIEnumerable
, but that would complicate the discussion.)I'd be happy to hear your opinions, preferences, and improvements!
At first, I was of the persuasion to allow some of my entities access to repositories (ie. lazy loading without an ORM). Later I came to the conclusion that I shouldn't and that I could find alternate ways:
Vernon Vaughn in the red book Implementing Domain-Driven Design refers to this issue in two places that I know of (note: this book is fully endorsed by Evans as you can read in the foreword). In Chapter 7 on Services, he uses a domain service and a specification to work around the need for an aggregate to use a repository and another aggregate to determine if a user is authenticated. He's quoted as saying:
Vernon, Vaughn (2013-02-06). Implementing Domain-Driven Design (Kindle Location 6089). Pearson Education. Kindle Edition.
And in Chapter 10 on Aggregates, in the section titled "Model Navigation" he says (just after he recommends the use of global unique IDs for referencing other aggregate roots):
He goes onto show an example of this in code:
He goes on to also mention yet another solution of how a domain service can be used in an Aggregate command method along with double-dispatch. (I can't recommend enough how beneficial it is to read his book. After you have tired from end-lessly rummaging through the internet, fork over the well deserved money and read the book.)
I then had some discussion with the always gracious Marco Pivetta @Ocramius who showed me a bit of code on pulling out a specification from the domain and using that:
1) This is not recommended:
2) In a domain service, this is good: