3
votes

I'm having some trouble with a few concepts in an application I am building using domain driven design.

I have the following layers:

  • Application
  • Domain
  • Infrastructure

So, let's assume I have the following classes:

  • Order
  • EmailService
  • OrderNotificationService
  • OrderApplicationService

Obviously, the Order goes in the domain layer and the OrderApplicationService goes in the application layer. The EmailService is a generic service for sending emails and is implemented in the infrastructure layer. The OrderNotificationService is a specific implementation for sending order notifications. The OrderNotificationService uses the EmailService to send the actual email.

So, my first question is: Would the OrderNotificationService be implemented as a domain service, application service or infrastructure service?

For my next question, let's assume the following objects:

  • Employee
  • SalesforceService

Let's say that when an employee gets added to the system, they should also get added to Salesforce. The SalesforceService is a service that uses the Salesforce api to register users. Would the SalesforceService be implemented as a domain service or a generic infrastructure service that the application service would use by sending the employee information?

Thanks for the advice.

2
What is the responsibility of the OrderApplicationService?smartcaveman

2 Answers

11
votes

This doesn't sound like DDD

There isn't much in your question which talks about your Domain Model. You mentioned an "Employee getting added to a system and a Salesforce", but outside of that I have no real sense of what your application is intended to do, in a business sense. My understanding of an "Employee" and a "Salesforce" are based on familiarity with the words, not on explication of their models in your system.

I don't really have a sense of what an "Order Application Service" is supposed to represent in terms of your model. I get an "Order" and "Order Notification". It seems like a "Customer" makes an "Order", and some "Subscriber" gets "Notified", but a lot of this is based on my prior knowledge of design patterns.

You should be able to describe the business domain model as it would work if computers didn't exist. If you need a computer term to explain the idea, it is probably mixing in something that is extrinsic from the model.

Obviously, you need to integrate the application logic with your domain logic, but this should not entail confusing your concerns. However, there are ways around this.

How you can fix it

  1. You can use interfaces instead of implementation specific classes to model services in your domain layer. This is known as the interface segregation principle. It makes sense that part of your model includes notifying the responsible employee when a customer places an order. However, there isn't necessarily any reason that the implementation of this notification should be coupled to its modeled purpose. There could be a supervisor making an announcement over an intercom in a crowded office or there could be an email being sent by an automated system. Both of these examples serve the same business purpose. Instead of embedding an email service in your domain layer you can have an IOrderNotificationService interface that simply contains a method void NotifyOrderReceived(Order order);. That way you have all of the business logic that you need in your domain layer without introducing unnecessary concerns like an "Email" implementation, or persistence to a database. I am guessing at this, but your OrderNotificationService and OrderApplicationService are really responses to the same event, but one has a database dependency and the other has an SMTP dependency. Both are infrastructure concerns.

Coding against a single interface will be sufficient in many cases. However, there is a problem that your domain objects now have a dependency on an injected service or a global variable. Also, this might indicate that these entities know too much about their dependency. A customer might not need to know the inner workings of how an order gets processed, but only that it was processed and they will receive what they ordered. Similarly, an Employee probably doesn't add himself to a Salesforce, because he doesn't know about it prior to becoming an Employee. All he knows is he just got a job.

There is a very good solution to this problem...

  1. You can use a "Domain Event" pattern. The basic idea is that the domain objects only know what just happened and how their state has been changed, but don't need to know anything about persisting or propagating that altered state. They handle their internal logic and then raise a "Domain Event". This is more similar to a Customer placing an Order and then yelling "Yo, I ordered this product!" or an Employee getting hired and then yelling, "Yo, I got a job!". Taking this approach will greatly simplify your domain logic and allow you to achieve a much cleaner separation of concerns. Udi Dahan has an excellent series of blog posts in which he explains both the logic behind leveraging the Domain Event pattern and provides a very simple but very effective implementation. Here are some links:

Now, in case you're the type of developer who likes to copy and paste code before fully understanding it, I suggest you start with the third of these posts. They document an evolution in Udi Dahan's thinking and experience with the pattern. The most sound code sample appears in the third article. Ideally, you would read all three, in order, so that you can follow his logic and actually understand how you can benefit from his approach and why it accurately represents "Domain Driven Design".

As added justification to the "Domain Event pattern", Eric Evans' 2009 review of what he had learned about Domain Driven Design since writing his groundbreaking book made a point that Domain Events were a significantly overlooked core building block in his book. An summary of his talk is available here, and links to the presentation are available here.

A few other resources that might help you successfully apply this pattern include Jimmy Bogard's article Strengthening your Domain: Domain Events and Martin Fowler's Domain Event article. Bogard has links to other helpful DDD blog posts from the referenced link.

In general,

If you really want to try applying domain driven design, you will be much more successful by getting a real understanding of what you are modeling and what you are implementing for what purpose. There is no implicit value in simply using a terminology that you are unfamiliar with and labeling your code as such. DDD can be extraordinarily helpful, but if you don't take the time to understand why you are making the distinctions and design decisions, you will end up with a lot of unnecessary abstractions and general confusion.

1
votes

The OrderNotificationService belongs to the domain layer. If you think it as a collaborator of the Order class, it should seat close to the Order class. IMO, I think the OrderNotificationService can be called OrderNotifier instead, whose responsibility is to publish notifications when order state changed. It is obviously an interface instead of a concrete class. It may be implemented by OrderNotificatoinService, which belongs to the either infrastructure or application layer. There is no need to make OrderNotificationService an interface.

The same applies to the SalesforceService. Think it as a collaborator of the Employee class, who's responsible for registering new employee information when an employee is created. It belongs to the domain layer. Same as the previous case, you may consider rename it to EmployeeRegister or something similar, which describe its role rather than its implementation. Implemented it with SaleforceService instead.

One side effect is that your domain objects (Order/Emplyee) depend on classes of the application/infrastructure layers indirectly. You may find it tricky to inject third party dependencies when creating your domain objects if they are instantiated by other domain objects. This article may be useful. http://thinkinginobjects.com/2012/09/05/abstract-factory-in-domain-modelling/