19

Probably similar questions have been asked many times but I think that every response helps to make the understanding of DDD better and better. I would like to describe how I perceive certain aspects of DDD. I have some basic uncertainties around it and would appreciate if someone could give a solid and practical anwser. Please note, these questions assume a 'classic' approach to DDD. This means using ORM's etc. Approaches like CQRS and event sourcing are not considered here.

  1. Aggregates and entities are the primary objects that implement domain logic. They have state and identity. In this context, I perceive domain logic as the set of all commands that mutate that state. Does that make sense? Why is domain logic related exclusively to state? Is it legal to model domain objects that have no identitiy or no state? Why can't a domain object be implemented as a transaction script? Example: Consider an object that recommends you a partner for a dating site. That object has no real state, but it does quite a lot of domain logic? Putting that into the service layer implies that the domain model cannot cover all logic.

  2. Access to other domain objects. Can aggregates have access to a repository? Example: When a (stateful) domain object needs to have access to all 'users' of the system to perform its work, it would need access them via the repository. As a consequence, an ORM would need to inject the repository when loading the object (which might be technically more challenging). If objects can't have access to repositories, where would you put the domain logic for this example? In the service layer? Isn't the service layer supposed to have no logic?

  3. Aggregates and entities should not talk to the outside world, they are only concerned about their bounded context. We should not inject external dependencies (like IPaymentGateway or IEmailService) into a domain object, this would cause the domain to handle exceptions that come from outside. Solution: an event based approach. How do you send events then? You still need to inject the correct 'listeners' every time you instantiate a domain object. ORM's are about restoring 'data' but are not primarly intended to inject dependencies. Do we need an DI-ORM mix?

  4. Domain objects and DTO's. When you query an aggregate root for its state does it return a projection of its state (DTO) or the domain objects themselves? In most models that I see, clients have full access to the domain data model, introducing a deep coupling to the actual structure of the domain. I perceive the 'object graph' behind an aggregate to be its own buisness. That's encapsulation, right? So for me an aggregate root should return only DTO's. DTO's are often defined in the service layer but my approach is to model it in the domain itself. The service layer might still add another level of abstraction, but that's a different choice. Is that a good advice?

  5. Repositories handle all CRUD operations at the aggregate root level. What about other queries? Queries return DTO's and not domain objects. For that to work, the repsitory must be aware of the data structure of the domain which introduces a coupling. My advice is similar to before: Use events to populate views. Thus, the internal structure is not made public, only the events carry the necessary data to build up the view.

  6. Unit of work. A controller at the system boundary will instantiate commands and pass them to a service layer which in turn loads the appropriate aggregates and forwards the commands. The controller might use multiple commands and pass them to multiple services. This is all controlled by the unit of work pattern. This means, repositories, entities, services - all participate in the same transaction. Do you agree?

  7. Buisness logic is not domain logic. From a buisness perspective the realization of a use case might involve many steps: Registering a customer, sending an email, create a storage account, etc. This overall process can impossibly fit in a domain aggregate root. The domain object would need to have access to all kind of infrastructure. Solution: Workflows or sagas (or transaction script). Is that a good advice?

Thank you

shaft
  • 2,147
  • 2
  • 22
  • 38
  • 3
    Some good points/questions are brought up here, but SO is not a discussion board. There are far too many questions and there are no clear answers. – EkoostikMartin Aug 13 '13 at 20:03
  • Judging by your questions, it seems you failed to get the spirit of DDD regarding certain points (domain services vs application services, how layers play together, etc). Others have already been answered many times here on SO. I suggest re-reading relevant chapters in the book, searching for answers here and coming back with separate questions for problems you still have trouble dealing with. – guillaume31 Aug 19 '13 at 12:19

2 Answers2

9

The first best practice I can suggest is to read the Evans' book. Twice.
Too many "DDD projects" fail because developers pretend that DDD is simply OOP done right.

Then, you should really understand that DDD is for applications that have to handle very complex business rules correctly. In a nutshell: if you don't need to pay a domain expert to understand the business, you don't need DDD. The core concept of DDD, indeed, is the ubiquitous language that both the coders, the experts and the users share to understand each other.

Furthermore, you should read and understand what aggregates are (consistency boundaries) by reading Effective Aggregate Design by Vernon.

Finally, you might find useful the modeling patterns documented here.

Giacomo Tesio
  • 7,144
  • 3
  • 31
  • 48
  • 3
    Thanks, I read the book but am still fighting to get it right in practice. If DDD is only for very complex buisness rules, then it's of limited use. Not every domain is very complex and I hoped that DDD can still give good advice in terms of architecture. I have to say that for all the DDD examples I found on the web, I haven't seen really complex buisness rules. In many cases where the buisness rules gets extraordinary complex (e.g. diagnostics in medicine), OOP aproaches tend to fail. Rules engines, probabilitstic models, numerical solvers etc. are often used to retrieve better results. – shaft Aug 14 '13 at 10:50
  • 1
    You are right shaft: **DDD is of limited use**! I apply it **only** for complex applications with budget over 1000000 €. Examples around the web **try** to show **how** to **code** domain models, but fail when it comes to the **why**. DDD is not software architecture: it's a development process built around the ubiquitous language. But DDD is not for object oriented languages only: I successfully applied it to an Haskell stock trader. OOP and DDD are mostly orthogonal, even if most of DDD frameworks and patterns around the web are OOP centric. – Giacomo Tesio Aug 14 '13 at 12:30
  • "with budget over 1000000 €". Is this hyperbole or a joke? – EkoostikMartin Aug 14 '13 at 13:20
  • Neither... why it looks like a joke? That's just my experience in financial software applications. – Giacomo Tesio Aug 14 '13 at 13:24
  • 2
    Are you saying that for you it's not worth it to use DDD unless the project is 1 mil euro, or that no project should ever use DDD without that size budget? I think you made some very insightful points, but this 1 mil euro comment detracts from the rest. – EkoostikMartin Aug 14 '13 at 13:28
  • No, I'm saying that (till now) I faced only one project under 1ml euro that required a DDD approach (the Haskell one). The smallest financial project that I've developed with DDD had a budget around 800000 (but evolved to over 1.5ml). This is just my experience. Still the point is: if the application add little value to the customer, probably it will have both a low budget and low business complexity. Indeed if it had low budget and high complexity no one would accept to code it. On the other hand, when the customer perceives it's complexity it will pay for it. **Here** DDD is strategic. – Giacomo Tesio Aug 14 '13 at 13:58
  • 1
    Sad to hear. This means that DDD is reserved for very few specialists that master the tricks. I have the sensation that every attempt to apply DDD for the casual project will result in a big laugh when the expert looks at it. However, there are numerous, equivalent ways for expressing "domain logic" as code. The ubiquitous language becomes the model of your requirements, but you still need a way to translate that into code. A methodology should give me advice/best practices on how to do that. After all DDD is also about patterns, they are just not clear enough. – shaft Aug 14 '13 at 14:36
  • 1
    @shaft DDD is not something "for specialist", but something that wont apply to all projects. This should be obvious for any technique: there's no ring to rule them all! If you apply DDD in a project that don't need it, it will become an expensive pain. It's the cheapest solution just in a few cases. Coders are not artists: you shouldn't care about what "specialists" say about your code. You should care about how your code satisfies all the requirements! If reliability (or readability, or anything else) is not a requirements, you shouldn't care. And you should care about all the requirements! – Giacomo Tesio Aug 14 '13 at 14:51
  • @GiacomoTesio - excellent advice. Practicality (and simplicity) wins out. – EkoostikMartin Aug 14 '13 at 18:52
  • So, for example, I am working at a company that uses microservices, some services written in ddd, a couple of weeks ago I had to create new service that should consume some event and send email to customers, this service should not need ddd, am I right? Because ddd is something about the whole system, not the particular one? – fuat Apr 19 '21 at 19:06
6

Despite my comment above, I took a stab at your points. (note: I'm not Eric Evans or Jimmy Nilsson so take my "advice" with a grain of salt).

  1. Your example "Consider an object that recommends you a partner for a dating site.", belongs in a Domain service (not an infrastructure service). See this article here - http://lostechies.com/jimmybogard/2008/08/21/services-in-domain-driven-design/

  2. Aggregates do not access repositories directly, but they can create a unit of work which combines operations from multiple domain objects into one.

  3. Not sure on this one. This should really be a question by itself.

  4. That's debatable, in theory, the domain entities would not be directly available outside the aggregate root, but that is not always practical. I consider this decision on a case-by-case basis.

  5. I not sure what you mean exactly by "queries". If modeling all possible "reading" scenarios in your domain does not seem practical or provide sufficient performance, it suggests a CQRS solution is probably best.

  6. Yes, I agree. UOW is a tool in your toolbox that you can use in various layers.

  7. This statement is fundamentally wrong "Business logic is not domain logic". The domain IS the representation business logic, thus one reason for using ubiquitous language.

EkoostikMartin
  • 6,831
  • 2
  • 33
  • 62
  • Thanks for your advice. Regarding point 7: If both terms are the same then why distinguish between them? There are many examples of buisness logic that span multiple bounded contexts, so I perceive the orchestration of multiple bounded context as the 'overall' flow. How would you call such a high level flow? – shaft Aug 14 '13 at 10:30
  • I agree with point 5. cqrs should be considered when we notice that there will be a large amount of read operations. – shaft Aug 14 '13 at 10:55
  • Thanks for your answer on point 1. Stateless services are first class in DDD, nice ;) I think this question is related to http://stackoverflow.com/questions/7306109/having-trouble-putting-real-world-logic-into-the-ddd-domain-layer?rq=1 – shaft Aug 14 '13 at 10:58
  • 1
    @shaft - for point 7 - logic spanning bounded contexts is common. Remember that each bounded context is brought together by the entire core domain. See this - http://stackoverflow.com/q/15345546/903056 – EkoostikMartin Aug 14 '13 at 13:23
  • In fact, BCs are THE most important concept of DDD. Because if you don't set a (context) boundary in a complex domain, you will never be able to model it right. Classical example: "customer". Is it someone coming into the store, someone who already bought something or someone we should invite to our x-mas sale? Well, who's asking? I.e. it's the context that determines the model and therefore the aggregate roots etc. And many BCs can have the same terms, but it is ubiquitous only in one! – Don Zampano Jan 07 '14 at 21:09