Reputation: 65
Questions: Should I turn my dependencies around and have the DomainModel
depend on Core
(which holds the systems interfaces and high level policy)?
Do we ever consider a rich domain model as representing implementation details?
Background: So I have my DomainModel
in a separate project with no outgoing dependencies. All of my subsystem services are in separate projects, and none of them know about each other. I also have a Core
project which holds all of the system specific things such as interfaces, enums, validation classes, extensions and other things common to all the services which I wouldn't classify as low level implementation details. Core
has no outgoing dependencies except to the DomainModel
, all of the services depend on Core
, and also DomainModel
.
My current thoughts: So I've heard design statements such as
"the domain model should have no outgoing dependencies"
and potentially in contrast
"high level policy shouldn't depend on low level implementation details"
and
"modules should depend on each other in the direction of stability"
I find as I develop the system the implementation of the domain model changes quite a lot, all of the business rules and objects are there, I wouldn't consider most of the domain model stable at all, possibly some of it such as the ValueObject
(s).
The advantage I see in having DomainModel
depend on Core
is that the high level policy then knows nothing of the implementation details of the domain model, which is also isolated from the rest of the system. Indeed, every other project would then just depend on Core
and still know nothing of each other. When I make a change in DomainModel
(which I often do as I develop) to build would recompile just that project, rather than the entire solution as is the case at present.
The disadvantage I see in achieving this extra amount of loose coupling is an increase in complexity? I would have to create interfaces for every single domain model object which would live in a special folder within Core
. For those interfaces I'd also want to drop the 'I' prefix and have say MoneyType : Money
[interface]. I imagine the only way I could then instantiate domain objects would be via abstract factories so I'd need a few more of those as well. Right now I do like being able to just instantiate concrete domain objects 'anywhere' in the system, almost like an extension to, or abstraction over, the BCL (which is part of the point of a domain model is it not?).
I can imagine the system working with either architecture, so is this just a classic case of competing design concerns - or am I completely missing something?
Edits: This highly voted answer seems to indicate that the domain model should be isolated with each object only exposing an interface to the rest of the system.
https://stackoverflow.com/a/821300/7417812
At the moment this feels better to me, as the rest of the system doesn't have unfettered access to the domain objects (thus the recompiling of them all every time there is a change). However, turning this dependency around for complete isolation will be no trivial task so I'm very open to more discussion and answers.
More edits: So I attempted the refactoring, at the point where I began trying to implement my own simple DI container I decided things were starting to become smelly and slightly ridiculous.
Any perceived benefit of complete DomainModel
isolation was being offset with an exponential increase in complexity and lines of code (at least for me). So I refactored the architecture around so that DomainModel
only depends on Core
which now only holds my design by contract classes, custom collections, annotations and common extensions I use. I took all the system specific interfaces and infrastructure out into a new project Infrastructure
which all the subsystem services depend on (no specific technologies in here so probably not a typical infrastructure layer?).
Everything feels better now however I'm back to depending on the concrete domain objects which I'm fine with. It wasn't at all a wasted exercise as I identified several improvements and simplifications of the DomainModel
, and was able to clarify Core
and identify the opportunity for Infrastructure
.
Upvotes: 3
Views: 1276
Reputation: 14064
I also have a Core project which holds all of the system specific things such as interfaces, enums, validation classes, extensions and other things common to all the services
You're describing agnostic code constructs and patterns which don't inherently belong in a particular layer.
Interfaces and enums, as long as they are about domain concepts, should be in the domain layer. Other interfaces and enums... well, wherever they fit best.
"Validation classes" is also very vague, but domain validation goes in the domain, command validation in Application layer, user input validation in the UI, etc.
Extension methods can be found in any layer.
I think you should get rid of that "Core" project that doesn't look really coherent and fan out all its content to the appropriate projects.
IMO, everything that is "high level policy" should go in Domain. Utility classes shared by all projects you could put aside in a library-like project or NuGet package, but there shouldn't be too many of these and I wouldn't call it Core anyway.
Upvotes: 1
Reputation: 17683
In the Onion architecture, one of the architectures that aligns well with DDD, the Domain
layer can be further split in two sub-layers:
So, you could have a Core
component that is shared between bounded contexts but I don't think that this should necessarily be in a separate project. It depends on how you want to propagate changes to this component to the other projects.
About the dependencies, the Domain sub-layer
will depend on the Core sub-layer
as it uses its low level classes but this does not break the Dependency inversion principle
as both are in the same layer. However, the (entire) Domain layer
should not depend on any other layers like Application
, Presentation
or Infrastructure
, the Domain layer
should remain pure, with no side effects and no dependencies. This rule should be respected in any architecture.
Upvotes: 4