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
.