15

I'm trying to apply now what I learned about DDD and I'm a little bit confused about the flow of dependencies in the Domain model.

My questions are:

  1. Should an Entity be aware of Factories, Repositories, Services in the domain?
  2. Should a Repository be aware of Services in the domain?

Another thing that is bothering my mind is how to treat to collections when I want to add and entity to the collection.

Let's say I'm developing a simple CMS. In the CMS I have an Article Entity and Tags collection which contains Tag Entities.

Now, in case I want to add a relation with a new tag. What would be the better way to do it? (Example in PHP)

$article->tags->add(TagEntity);
$articleRepository->save($article);

or I can do it with a service.

$articleService->addTag($article, TagEntity);

What do you think?

Thanks.

tounano
  • 859
  • 2
  • 9
  • 17
  • If you're developing a "simple CMS", DDD might not be the best pattern to go with. According to Evens, DDD is justified when the domain is complex. – Steven Dec 24 '12 at 11:23
  • 2
    Thanks. I'm not developing a CMS. I just gave this example because it was understandable without going deep inside my domain. – tounano Dec 24 '12 at 11:27
  • See also: http://stackoverflow.com/questions/13527621/model-service-decoupling-what-if-my-model-needs-a-service I had similar questions – Matthieu Napoli Dec 27 '12 at 16:00

5 Answers5

33

Entities and Value Objects should never be dependent on anything except for each other. These are the most fundamental of all the building blocks of DDD. They represent the concepts of Your problem domain and thus should focus on the problem. By making them dependent on Factories, Repositories and Services You make that focus blur. There is another problem with having a reference to Services in Entities and Value Objects. Because Services also possess the domain logic You will be tempted to delegate some of the responsibilities of the domain model to Services which eventually may lead to the Anemic Domain Model.

Factories and Repositories are just helpers used for creation and persistence of Entities. Most of the time they just have no analogy in the real problem domain, so having a reference from Factories and Repositories to Services and Entities would make no sense according to the domain logic.

Regarding the example You provided, this is how I would implement it

$article->addTag($tag);
$articleRepository->save($article);

I wouldn't give the direct access to the underlying collection, because I might want the Article to perform some domain logic (imposing constraints, validating) on the Tag before adding it to the collection.

Avoid this

$articleService->addTag($article, $tag);

Use Services only to perform operations that don't belong to any Entity conceptually. First, try to fit it to an Entity, make sure it doesn't fit any. And only then use a Service for it. This way You won't end up with anemic domain models.

UPDATE 1

A quote from Eric Evans's "Domain-Driven Design: Tackling Complexity in the Heart of Software" book:

SERVICES should be used judiciously and not allowed to strip the ENTITIES and VALUE OBJECTS of all their behavior.

UPDATE 2

Somebody has downvoted this answer and I don't know why. I can only suspect the reason. It could be about the references between Entities and Services or it could be about the example code. Well, I can't do much about the example code, because it was my opinion based on my own experience. But, I did some more research on the references part and here is what I came up with.

I am not the only one who thinks that referencing Services, Repositories and Factories from Entities is not a good idea. I found similar questions here in SO:

There are also some good articles on the subject, especially this one How not to inject services in entities which also presents a solution, if You desperately need to call a Service from Your Entity, named Double Dispatch. Here is an example from the article ported to PHP:

interface MailService
{
    public function send($sender, $recipient, $subject, $body);
}

class Message
{
    //...
    public function sendThrough(MailService $mailService)
    {
        $subject = $this->isReply ? 'Re: ' . $this->title : $this->title;
        $mailService->send(
            $this->sender, 
            $this->recipient, 
            $subject, 
            $this->getMessageBody($this->content)
        );
    }
}

So, as You can see You don't have a reference to the MailService service inside Your Message entity, instead it's passed as an argument to the entity's method. The same solution is proposed by the author of this article "DDD: Services" at http://devlicio.us/ in the comments section.

I have also tried to look at what Eric Evans says about this in his "Domain-Driven Design: Tackling Complexity in the Heart of Software" book. Having briefly searched, I didn't find the exact answer, but I found an example where an Entity actually calls the service statically, that is without having a reference to it.

public class BrokerageAccount {
    String accountNumber;
    String customerSocialSecurityNumber;

    // Omit constructors, etc.

    public Customer getCustomer() {
        String sqlQuery =
            "SELECT * FROM CUSTOMER WHERE" +
            "SS_NUMBER = '" + customerSocialSecurityNumber + "'";
        return QueryService.findSingleCustomerFor(sqlQuery);
    }

    public Set getInvestments() {
        String sqlQuery =
            "SELECT * FROM INVESTMENT WHERE" +
            "BROKERAGE_ACCOUNT = '" + accountNumber + "'";
        return QueryService.findInvestmentsFor(sqlQuery);
    }
}

And the note below states the following:

Note: The QueryService, a utility for fetching rows from the database and creating objects, is simple for explaining examples, but it's not necessarily a good design for a real project.

If You have a look at the source code of the DDDSample project I've mentioned above, You'll see that Entities don't have any reference to anything except for the objects in the model package, i.e. Entities and Value Objects. By the way, the DDDSample project is described in the "Domain-Driven Design: Tackling Complexity in the Heart of Software" book in detail...

Also, one more thing I would like to share with You is a similar discussion on the domaindrivendesign Yahoo Group. This message from the discussion quotes Eric Evans on the subject of model objects referencing Repositories.

Conclusion

To summarize, having a reference to Services, Repositories and Factories from Entities is NOT good. This is the most accepted opinion. Even though Repositories and Factories are citizens of the Domain layer, they are not part of the problem domain. Sometimes (e.g. in the Wikipedia article on the DDD) the concept of the Domain services is called Pure Fabrication which implies that the class (Service) "does not represent a concept in the problem domain". I'd rather refer to Factories and Repositories as Pure Fabrications, because Eric Evans does say something else in his book about the concept of Services:

But when an operation is actually an important domain concept, a SERVICE forms a natural part of a MODEL-DRIVEN DESIGN. Declared in the model as a SERVICE, rather than as a phony object that doesn't actually represent anything, the standalone operation will not mislead anyone.

According to the above-said, sometimes calling a Service from Your Entity might be a sane thing to want. Then, You can use the Double Dispatch approach, so that You won't have to keep a reference to the Service in Your Entity class.

Of course, there are always some people who disagree with the mainstream opinion like the author of Accessing Domain Services from Entities article.

Community
  • 1
  • 1
zafarkhaja
  • 2,562
  • 1
  • 20
  • 22
  • Thanks for your help. You mentioned validation, from what I understand Entities and Values shouldn't have any logic except of representing the domain. From what I understand the validation logic should be in the Factories, isn't it like that? – tounano Dec 25 '12 at 14:46
  • Actually, here is another interesting thought. How would you persist something, after the creation? Option 1) The factory adds the entity to the repository. 2) You add a new object manually to the repository. Thanks. – tounano Dec 25 '12 at 14:50
  • On validation. I mentioned it just as an example of domain logic, it could be anything else. Anyway, if this is what domain logic dictates, validation should go in Entities. It shouldn't necessarily be about checking for tag's length or illegal characters, if this is what bothers You. A valid tag could imply that the tag is added by the article's author and then in the `addTag($tag)` method You would check if this is the case. – zafarkhaja Dec 25 '12 at 15:55
  • On persistence. I would go with Option #2. The only responsibility of Factories should be creation of Entities. You tell it to create an Entity and then it's up to You whether You want to persist it or not. – zafarkhaja Dec 25 '12 at 16:00
  • See also this question/answer http://stackoverflow.com/questions/13527621/model-service-decoupling-what-if-my-model-needs-a-service that doesn't go in the same direction as your answer – Matthieu Napoli Dec 28 '12 at 14:53
  • @Matthieu, the reason that answer doesn't go in the same direction as mine is because I don't agree with that. And the reason I don't agree with that is because what that answer suggests (dependence on abstractions) is a general OOP rule (Dependency Inversion Principle) which is not necessarily applicable here because DDD itself may impose semantic constraints on the code. If we were to answer a question "How should an Entity depend on a Service?" that would make a perfect answer. But the main question here is "Is it allowed for an Entity to depend on a Service in the first place?"... – zafarkhaja Dec 29 '12 at 09:21
  • @zafarkhaja Thanks. I agree with you and I also think that Entities should be both service and persistence ignorant. What happens now is Im confused of how to implement the persistence of such thing. For example If I do `$article->addTag($tagFactory->create('New Tag'));` and then `$articleRepository->save($article);` It should persist the new tag as well right? How would you implement it? How would you add a relation between an article and a tag? One way I thought of doing that is allowing entities and aggregates to keep state (NEW,CLEAR, CHANGED) and inject repositories inside repositories. – tounano Dec 31 '12 at 08:54
  • 1
    @tounano, use the ORM tools, like Doctrine, for example. They will take care of persisting all Your entities. The ORM tools make heavy use of the Identity Map pattern, which keeps track of all the loaded entities, so that You don't load them twice, and the Unit Of Work pattern, which keeps track of states of the entities, so that You don't persist what's not changed (pretty much the same as what You've come up with). Entities and aggregates shouldn't care about the entities' states because this logic doesn't belong to the Domain layer. – zafarkhaja Jan 04 '13 at 17:30
5

Should an Entity be aware of Factories, Repositories, Services in the domain?

An entity should never reference a repository or an application service. It is acceptable for entities to reference a factory if it uses it to create a constituent entity. It is also acceptable for an entity to have a dependency on a domain service if it uses that services for certain behavior.

Should a Repository be aware of Services in the domain?

Generally no. A repository should only be responsible for persistence.

Now, in case I want to add a relation with a new tag. What would be the better way to do it?

It depends on which layer you refer to. In a typical DDD architecture, you'd have both pieces of code. You'd have an article application service which encapsulates the domain and provides a granular method such as addTag where you'd pass an article ID and a tag ID. This method would retrieve the appropriate article and tag instances (if needed) and then:

$article->tags->add(TagEntity);
$articleRepository->save($article);

All outer layers depending on this domain would communicate with it through the application service.

eulerfx
  • 36,769
  • 7
  • 61
  • 83
  • In that case, how would you implement lazy loading of entities inside aggregates. For example, if I don't need to use the tags, I shouldn't query for them. If entities aren't aware of repositories, what would you do? Thanks – tounano Dec 25 '12 at 07:52
  • The way lazy loading it achieved in this case is through the use of reflection and proxies (in Hibernate for instance). I've not used PHP for years and I'm not sure if PHP has any ORMs that will support this. However, another important thing to be aware of is that [lazy loading can be problematic](http://gorodinski.com/blog/2012/06/16/orm-lazy-loading-pitfalls/) and could be avoided with the use of [read-models](http://gorodinski.com/blog/2012/04/25/read-models-as-a-tactical-pattern-in-domain-driven-design-ddd/). – eulerfx Dec 25 '12 at 17:29
  • @tounano That's the reason I disagree with eulerfx: reflection and "tricks" like that shouldn't be mantatory to allow lazy-loading. An entity can use a domain service interface (the implementation can be in any layer). As a repository is a service, the entity can use a repository interface (which is in the domain layer) whereas the repository implementation is in the infrastructure layer. See my answer for more details. – Matthieu Napoli Dec 28 '12 at 13:00
  • "An entity should never reference a repository or an application service" where did you get that from ? – NimChimpsky Dec 28 '12 at 13:04
3

Should an Entity be aware of Factories, Repositories, Services in the domain?

  • Application services: no
  • Domain services: yes, because they are in the domain layer
  • Factories: yes, because they are in the domain layer
  • Repository interfaces: yes, because they are in the domain layer
  • Repository implementations: no, because they are in the infrastructure layer

Notice the differente between interface and implementation: that's why you should use interface & implementations.

And FYI, Factories and Repositories are services after all, so you can generalize:

  • Service interfaces: yes if they are in the domain layer

Easy

A domain service is one which is defined within the domain layer, though the implementation may be part of the infrastructure layer. A repository is a domain service whose implementation is indeed in the infrastructure layer, while a factory is also a domain service whose implementation is generally within the domain layer.

(Source: http://www.methodsandtools.com/archive/archive.php?id=97p2)

Should a Repository be aware of Services in the domain?

Usually no, why would it after all? The repository manage persistence. But I don't think that's "prohibited" because the infrastructure layer (persistence) knows about the domain layer.

Another thing that is bothering my mind is how to treat to collections when I want to add and entity to the collection.

Prefer the OOP approach when possible:

$article = new Article();
$article->addTag($tag);
$articleRepository->save($article);

I makes way more sense.

a domain service is any business logic that does not easily live within an entity.

(http://www.methodsandtools.com/archive/archive.php?id=97p2)

or also:

When a significant process or transformation in the domain is not a natural responsibility of an ENTITY or VALUE OBJECT, add an operation to the model as a standalone interface declared as a SERVICE.

(Eric Evans)

To sum up, create a domain service if you feel you need to, this is not automatic.

Matthieu Napoli
  • 48,448
  • 45
  • 173
  • 261
  • What makes that code object-oriented? Just because it uses objects and methods doesn't make it object-oriented. OOP is about abstraction and encapsulation. Instead, the code exposes the internal data (`tags` collection) and its implementation details. Now that the client code is aware of the details You can't easily change the implementation of the `tags` collection, let's say, for `SplFixedArray` implementation without changing the client code. But, if properly encapsulated (`$article->addTag($tag)`), it's easy to do so. – zafarkhaja Dec 28 '12 at 12:34
  • The domain services are not used because the logic is too "big". How much is that "big", anyway? A quote from Eric Evans's book: "When a significant process or transformation in the domain is not a natural responsibility of an ENTITY or VALUE OBJECT, add an operation to the model as a standalone interface declared as a SERVICE." – zafarkhaja Dec 28 '12 at 12:45
  • @zafarkhaja SORRY okay! I really thought his example what `addTag($tag)` and I copy-pasted it without paying attention. I'll edit my answer because obviously I agree with you. Regarding the service approach can you read the quote? My phrasing is not exact, that's the reason I added the quote. Now I'll edit that too with your quote. – Matthieu Napoli Dec 28 '12 at 12:52
  • 1
    "And FYI, Factories and Repositories are services after all" No they are not, thats the whole point. – NimChimpsky Dec 28 '12 at 13:20
  • @NimChimpsky According to Dan Haywood they are, see the quote in my answer. Why wouldn't they be? – Matthieu Napoli Dec 28 '12 at 13:48
  • 1
    because it devalues the whole notion of having the separate definitions. Its like talking about apples and oranges, and then saying well an apple can be an orange if you look at it differently or paint it. The link uses the term "domain service" adding a whole term to an already apparently complex arhitectural desgin philopshy. If factory, repository etc are services, why even use the terms factory,repository at all ? – NimChimpsky Dec 28 '12 at 13:50
  • @NimChimpsky A Granny Smith apple is an apple, it doesn't make that concept useless. The fact that repositories are a kind of service doesn't make them useless too. Do you have any source to back that up anyway? – Matthieu Napoli Dec 28 '12 at 13:57
  • also you recommned "$article->addTag($tag);" so you move the save functionality to within the article domain object ? – NimChimpsky Dec 28 '12 at 13:57
  • @NimChimpsky No... I just didn't write it for clarity's sake but if you need that line to understand the example then I'll add it – Matthieu Napoli Dec 28 '12 at 13:59
  • @Matthieu I think its important as it actually more method calls, less oop ? Many people would propose the save functionality is included on domain object (article in this case). Also, that link is not the most readable user friendly article, highlighig the difference between domain service and infrastrcutre service is needlessy complex, imho. And saying a repository is a service- is just plain confusing and contradicts the original docs on the matter. – NimChimpsky Dec 28 '12 at 14:01
  • The original docs I link to in my answer show repostory etc as all separate - obviously they would be otherwise why even have the separate definitions ?. that article is the first time I have seen someone say "a repository is a service" - I just find it weird, it doesn't make sense. You can argue its merit, but to me it just confuses the matter ... a service is x, a repository is y and so on. Don't start saying x can equal y. – NimChimpsky Dec 28 '12 at 14:07
  • "A Granny Smith apple is an apple" Huh ? That is anagalous to my holidayService being a service, but not holidayService being a repository (a granny smith is not an orange). – NimChimpsky Dec 28 '12 at 14:26
  • @NimChimpsky if you quote that sentence, quote it entirely. I was saying that the concept of Granny Smith is not rendered useless just because it is a kind of apple. It is still useful to differentiate Granny Smiths from other apples. – Matthieu Napoli Dec 28 '12 at 14:51
  • 1
    True, but it also confuses things when you say a granny smith is an orange. In fact its analogous to saying an orange (repository) is a granny smith apple (domain service). – NimChimpsky Dec 28 '12 at 14:54
  • @NimChimpsky I am not saying that. OK a better example : a square is a kind of rectangle. The definition of a square is useful even if it **is** a rectangle. A repository is a kind of service. – Matthieu Napoli Dec 28 '12 at 15:03
  • @Matthieu I don't think a repository is a "kind of service". A service is a service, a repository is repository, they are separate hence the separate definitions and implementations - given in yr basic building blocks of DDD link : http://en.wikipedia.org/wiki/Domain-driven_design#Building_blocks_of_DDD – NimChimpsky Dec 28 '12 at 15:05
  • @NimChimpsky A square is a square *and* a rectangle > "OMG things are not just one thing only? I don't believe it it's magic!" – Matthieu Napoli Dec 28 '12 at 15:09
  • @Matthieu do you really fail to see the point I am making ? Some of the links you use highlight the *differences* between a service and repository. Saying that are in some way equivalent just confuses things, and is incorrect. That Dan hayward blog is the only place I have seen it attempted.Does it really make sense to you to say a "repository is a service" and do you not see the logical incosistency? – NimChimpsky Dec 28 '12 at 15:12
  • @NimChimpsky You keep putting words in my mouth. I'm **not** saying that they are *equivalent*! I'm saying one is a *subset* of the other. What is a domain service? It's a service that is in the domain layer (to handle domain problems). A service is "a set of related software functionalities that can be reused for different purposes". This definition is extremly generic, that's because that's what a service is! A set of related functions and that's it. A repository is a set of related functions right? It's about persistence? OK let's name that a repository to distinguish it. – Matthieu Napoli Dec 28 '12 at 15:19
  • 1
    Service : When an operation does not conceptually belong to any domain object or when more than one Domain object is required. Repository: methods for retrieving domain objects. Its simple. – NimChimpsky Dec 28 '12 at 15:19
  • @NimChimpsky Retreiving domain objects **doesn't not belong to a domain object**... – Matthieu Napoli Dec 28 '12 at 15:20
  • @Matthieu huh ? Double negatives, always a good sign. I have no idea what you are trying to say. If I was in a development meeting and I said all service classes, my co-workers would not assume I also meant repositories. – NimChimpsky Dec 28 '12 at 15:21
  • @NimChimpsky ... I know. "Repository: methods for retrieving domain objects." "Retreiving domain objects doesn't belong to a domain object." => a repository is a service. (sorry for the typo about the double negative) – Matthieu Napoli Dec 28 '12 at 15:22
  • I have not used a double negative. I have no idea what yr last two comments mean. – NimChimpsky Dec 28 '12 at 15:23
  • @NimChimpsky Yes because in the "common language" you don't mean "repositories" when you say "service" – Matthieu Napoli Dec 28 '12 at 15:23
  • @Matthieu I thought you had just argued the exact opposite. And yr answer "And FYI, Factories and Repositories are services after all". No it turns out "common language" is something else in yr opinion? What were we using before if not "common language". – NimChimpsky Dec 28 '12 at 15:25
  • OMG ok I try again. A repository is for retrieving entities, and and service is for operations that do not conceptually belong to a domain object. Well it turns out that retrieving entities doesn't belong to a domain object, so that means that the repository fits in the definition of a service. – Matthieu Napoli Dec 28 '12 at 15:25
  • Do you use service to refer to repositories when discussing development with co-workers ? If not don't do it here. – NimChimpsky Dec 28 '12 at 15:26
  • @NimChimpsky No. That's why I said "And FYI, Factories and Repositories are services **after all**". That's like "and square are rectangles after all, so everything you know about squares also apply to rectangles" – Matthieu Napoli Dec 28 '12 at 15:28
  • I see the point you are making, however I still find it rather misleading, especially if someone were new to DDD. – NimChimpsky Dec 28 '12 at 15:32
  • There are alot more abstraction layers to be added in a domain . You should never reference objects outside an aggregate (except value objects and entities) . For example if you use factories for creation of valid Aggregates , the factory should enforce a valid entity state . So it can call a repository or an event or a service to create a proper entity . You should not use those objects in the entity . – Geo C. Jan 09 '14 at 22:57
1

I'll answer this with the precondition that I don't think there is a right answer, just different approaches.

Thinking in terms of domain objects I would say the first approach is DDD. You are dealing purely with domain objects.

I do think however there are uses for a service object that exposes this as part of an API/Service layer. In this case you would wrap your code from #1 within your service #2. This allows you to avoid exposing your domain objects to external consumers - and you can keep the external interface/API unaltered while updating your domain model.

This however is just one opinion.

rmar
  • 11
  • 1
  • Thanks. In that case, how would you treat removing objects from a collection? What do you think about the first question regarding who should be aware of who? Thanks. – tounano Dec 24 '12 at 11:29
0

First thing first, don't get to hung up on it - its easy to over engineer by creating unnecessary service classes etc. Less code is good. Check out the original source material, and the code in either Java or C#.

1) Should an Entity be aware of Factories, Repositories, Services in the domain?

It can if required. For example my (java) class annotated with @Entity can also be annotated with @Configurable and have a session/other classes injected into it. That is the point - to encapsulate all necessary business logic and expose a clear simple api located on one Domain class.

2) Should a Repository be aware of Services in the domain?

No. But the opposite is likely, a Service would use a repository.

Services are used when more than one domain object/entity/root aggregate is utilized. So assuming a TAG is a separate entity, this would be fine :

$articleService->addTag($article, TagEntity); 

However if Tag is anot another root aggregate, you could just do

$article->tags->add(TagEntity);

And article itself does the save (without any other calls) by having a repository/dao injected inside it.

NimChimpsky
  • 46,453
  • 60
  • 198
  • 311
  • This answer is imho not sufficient especially the first part. Imagine an aggregate UserAddresses offering a addAddress function. Should that function also save to Repository? I don't think so. In our DDD project, the DomainModel module does not even have a IoC framework like Spring as dependency. Dependency Injection in Domain Objects can only happen by passing the dependency as method parameter. Moreover it would be difficult to inject dependencies when the Aggregate is constructed out of technology such as MongoDb entity. You would have to manually inject them which is code smell². – Stefano L Nov 10 '17 at 11:11