Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Domain Driven Design and IoC/Dependency Injection

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.

like image 921
tounano Avatar asked Dec 24 '12 10:12

tounano


People also ask

What is IoC and dependency injection?

Dependency Injection is the method of providing the dependencies and Inversion of Control is the end result of Dependency Injection. IoC is a design principle where the control flow of the program is inverted. Dependency Injection is one of the subtypes of the IOC principle.

Are IoC and DI the same?

Inversion of Control(IoC) is also known as Dependency injection (DI). The Spring container uses Dependency Injection (DI) to manage the components that build up an application and these objects are called Spring Beans. Spring implements DI by either an XML configuration file or annotations.

What is domain-driven design used for?

Domain-Driven Design(DDD) is a collection of principles and patterns that help developers craft elegant object systems. Properly applied it can lead to software abstractions called domain models. These models encapsulate complex business logic, closing the gap between business reality and code.


1 Answers

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:

  • Is it ok for entities to access repositories?
  • DDD - Dependecies between domain model, services and repositories
  • DDD - the rule that Entities can't access Repositories directly
  • DDD Entities making use of Services

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.

like image 134
zafarkhaja Avatar answered Sep 22 '22 05:09

zafarkhaja