Quoting DDD theory:
The application layer is thin in terms of domain logic – it merely
coordinates the domain layer objects to perform the actual work.
When it comes to modularization, and assuming that the module containing the domain entities and the interfaces of the domain services belongs to the domain layer, the application layer depends on the domain layer, which breaks the dependency inversion principle.
The implementation of the high-level component’s interface by the low
level component requires that the low-level component package depend
upon the high-level component for compilation, thus inverting the
conventional dependency relationship.
What am I missing?
I add an UML diagram to clarify the problem I see.
- The Persistence Layer depends upon an abstration in the Domain Layer
-> DIP ok! - The Application Layer depends upon an abstraction in the Domain Layer -> Does this break the DIP?
2
It doesn’t break DIP because Domain is the highest level, higher than Application, and doesn’t have a dependency on it. The reverse (Domain depending on Application) would break DIP.
Also, the “should depend on abstraction” part of DIP doesn’t necessarily apply here, because domain entities can’t be abstracted — they are already a pure conceptual model of your domain. The only exception may be Domain Services, because you could place an interface in front of those.
As a side note, you generally don’t need to leverage dependency inversion inside the Domain model itself, because
- Domain entities have few to no collaborators
- The ones they have are well identified (ubiquitous language) and often not polymorphic in nature
- Domain resides entirely in memory with no external communication (3d party framework, network, disk, etc.) involved, so it can be tested with fast integration tests without needing mocks.
10
The Dependency Inversion Principle has one major exception: At some point you must do something concrete. An example is in order.
Let’s say you’ve got a Blogging application. You’ve got two tables in the database, and two domain models, say Blog
and Post
. Let’s also say you are working with an MVC framework like ASP.NET MVC, Ruby on Rails, etc.
Now, let’s say you’ve got another class called BlogPostsController
implementing the basic CRUD operations for blog posts.
The framework implements the Dependency Inversion Principle by not hard coding the following lines anywhere in its code base:
new BlogPostsController();
The framework looks at the incoming URL and constructs the name of the controller class dynamically. The framework doesn’t have a hard dependency on your BlogPostsController
class.
Now, let’s look at the controller. Inside your controller you see new Post()
peppered all over. This is not a violation of the Dependency Inversion Principle because at some point you, as a programmer, need to actually save a blog post to the database.
The Dependency Inversion Principle is mainly aimed at dependencies that aren’t laser focused on the basic intent of a class, for instance creating a new “controller” in an MVC framework. You don’t want a hard coded switch
or if
statement in order to do that. Authentication is another area where DIP is important because your BlogPostsController
class shouldn’t care how browser cookies are handled, or if the user logs in using a custom login page wired to a Database, or using Windows authentication or plain text authentication in the browser wired to LDAP behind the scenes.
1
The DI means your Application layer shall not depend directly on the Domain Service classes, but on abstract interfaces of those service classes (actually, your diagram is already showing this). The only thing which is debatable is if those interfaces should be placed in the Domain Layer. You better place them outside, in a “Service Interface” layer, so they can be referenced from the Application layer as well as from the Domain layer. This way, you have no direct dependendencies between Application layer and Domain layer, in none of the two possible directions.
Of course, as Greg has already pointed out, somewhere in your application you have to wire everything together and actually create non-abstract instances of your Domain Service classes. Either you use a DI framework for this purpose, or you do this manually in a kind of “infrastructure” part of your program, outside of any of the classic “layers”. Neither a DI framework, nor a manual start-up infrastructure is relevant in the sense of the DIP.
13
Cannot yet comment so here we go: Your misunderstanding becomes very obvious if you look at graphs of a “hexagonal architecture”. Essentially DDD just wants all your sourcecode dependencies to point “inwards” into your application core, into your domain.
The architecture you layed out does not violate this principle. You merely use the DIP to topple the layers persistence and application, avoiding for the dependency to point “downwards”.