I would like to have one or more libraries of reusable classes that are basically value objects, such as Address, PhoneNumber, EmailAdress, containing mostly properties and a few supporting methods. How can my Domain layer use these without breaking the rule that the Domain Layer should not contain external references, and without defining them as interfaces/abstract classes in the Domain Layer?
... without breaking the rule that the Domain Layer should not contain external references
I think your definition of 'external references' requires some reevaluation. It is hard to imagine a domain layer that does not reference anything. In C# and Java you will reference at least basic numeric types, dates and strings. I also don't see any harm in referencing external libraries like Noda/Joda time. On the other hand, you of course would not want to reference any heavy technical libraries like persistence, communication, UI etc.
So I would say that you can build your own reusable library referenced from domain but it requires a very careful consideration, and is often not worth the coupling that it will create. I would use a following criteria for every type:
Should be context-independent. EmailAddress for example is relatively independent of the context it is used from. Address on the other hand may have a different meaning depending on a Bounded context.
Should be stable (does not change often).
Should not hide any out-of-process communication (db, network etc)
Should not have any dependencies of its own (other than standard Java/C#)
I think that what you're referring to is a shared kernel.
Shared Kernel – This is where two teams share some subset of the
domain model. This shouldn’t be changed without the other team being
consulted.
While this looks great at first, since we are drilled not to repeat ourselves, be aware of the pitfalls:
The concepts should have the same meaning in every context. Some of these concepts hold subtle nuances depending on the context. Ask your domain expert.
Changes are more expensive; it might be cheaper to duplicate these few classes so that you can change them on your own than to have to consult multiple teams when something changes.
Stability cuts both ways. If you pull an entity out into each domain, then any changes have to be executed across multiple projects. If you don't, then changes have to be coordinated across multiple domains. The logistics of the former are easier than the latter, but the work involved in the latter can be greater. Either way, you have to test the changes on each platform.
And unless the entity is mature with a relatively well-defined semantics, my experience is that almost everything changes. So stability is nice, but might be a bit of a red herring.
That being said, I like (and +1) #Dmitry.
Related
I am trying to learn about details of domain driven design and i came to this question.
I found many examples with:
Defining repository interface within the domain
Defining repository implementation somewhere else
Inject repository interface into aggregate root
On the other hand, there are examples that strictly go against it and do all repository related stuff from service.
I cannot find authoritive answer and explanation: is it considered a bad practice and if so - why?
I cannot find authoritive answer and explanation: is it considered a bad practice and if so - why?
Yes, mostly because a number of different concerns get confused.
Aggregates define a consistency boundary; any change of state should be restricted to a collection of related entities that are all part of the same aggregate. So once you have looked up the first one (the "root" entity), you should be able to achieve the change without needing to examine any data other than this graph of domain entities and the arguments that you have been passed.
Put another way, Repository is a plumbing concern, not a domain concern. Your domain entities are responsible for expressing your domain, without infrastructure concerns getting mixed in.
To have, for example, Aggregate.Save() method that would inside use IRepository interface to save.
Aggregate.Save() definitely indicates a problem. Well, two problems, to be precise: Save probably isn't part of your ubiquitous language, and for that matter its likely that Aggregate isn't either.
Save isn't a domain concern, it's a persistence concern - it just copies data from your in memory representation (volatile storage) to a durable representation (stable storage). Your domain model shouldn't need to know anything about that.
One of the reasons you found "many examples with" is that getting these concerns separated correctly is hard; meaning you really need to think deeply about the problem to tease them apart. Most examples don't, because teasing things apart isn't critical when you always deploy everything together.
1)
Evan's book, pg. 415:
Also, the critical aspects of the domain model may span multiple
Bounded Contexts, but by definition these distinct models can't be
structured to show their common focus.
a) I assume the quote is implying that Core Domain CD can span several Bounded Contexts BCs?
b) I assume BCs within CD should only contain core elements, but no generic elements? If so, doesn't that mean we should always design BCs ( those contained by CD ) with Core Domain in mind? In other words, we should have some general idea what CD is even before we begin designing BCs?
c)
... but by definition these distinct models can't be structured to
show their common focus
I realize that BCs shouldn't be structured such that outside world would be able to immediately figure out how all the parts ( ie BCs ) fit together and what their common purpose is, but is author implying that such a structure ( which would implicitly convey the common purpose of different BCs ) couldn't happen even by accident? If so, why?
2) Domain Model may have several Generic Subdomains GSs , but can a single GS span multiple BCs?
UPDATE:
1)
b)
I assume BCs within CD should only contain core elements, but no
generic elements? ...
One should certainly have an idea of what the core domain is when
defining BCs. As stated, ideally, they should be one-one. However, a
BC may be defined to fulfill needs of of a system in a non-ideal
state.
I assume you're implying that in non-ideal situation BC within CD may also contain some non-core elements and also in non-ideal situation CD may contain more than one BC?
c)
A domain spans multiple BCs but despite explicit boundaries, domain
behavior can certainly span BCs. A context map can describe such
cross-BC interactions. The quote itself is based around the idea of a
domain vision statement the purpose of which is to highlight the value
of the core domain and possibly explain the relationship to BCs.
But why is author using the term "by definition", as if to imply there is no way that BCs could accidentally also be structured such that they would show their common focus?
2)
Domain Model may have several Generic Subdomains GSs , but can a
single GS span multiple BCs?
Multiple BCs can make use of a single generic sub-domain. I would
avoid the term "spans" here because that overemphasizes the importance
of the generic sub-domain for the entire domain model.
a)
Multiple BCs can make use of a single generic sub-domain
Not sure I understand your reply. Are you saying that a single GS can contain multiple *BCs*?
b)
I would avoid the term "spans" here because that overemphasizes the
importance of the generic sub-domain for the entire domain model.
Perhaps a useless question, but could you elaborate on why using the term "span" would make Generic Subdomain appear more important than it actually is?
REPLYING TO Giacomo Tesio:
1)
b)
No, some generic elements often play a key role in the Core Domain.
See for example Time, Currency and Money that are present in many
Shared Kernel: they are really generic but important to the Core
Domain rules.
So if generic element ( such as Time, Currency and Money ) is also used by Core Domain, then only implementation option is Shared Kernel ( ie this generic element is shared by both Core Domain and any other subdomain(s) that needs it ), but if generic element is used only by Core Domain, then we shouldn't bother with Shared Kernel, but should instead define this generic element directly within Core Domain ?
1)
c) Context boundaries are defined after term's semantics. In a BC, no
term should mean more than one thing (see SRP). When you see that a
class has more than one meaning in the domain expert's mind, you know
that you have mixed differnt BC.
Could you expand on your answer a bit, since I fail to understand how your answer relates to my question?
SECOND UPDATE:
1)
b)
It may also be that a single BC contains multiple sub-domains. This is
usually not ideal because it likely indicates a conflated BC.
When reading the book, I haven't pay much attention to author's usage of the term "subdomain", but I'm pretty certain that the book doesn't offer a thorough definition of what a subdomain is. So what exactly is considered a subdomain? Just a bunch of logically related domain concepts? If yes, then I assume a subdomain should never span several BCs?
2)
a)
A signle GS can be used by multiple BCs. This is so because the
sub-domain is generic. So the GS doesn't contain the BCs; instead, it
is referenced by the BCs.
From your reply it seems you're implying that Generic Subdomains are never implemented as BCs? Why not, since in my opinion different Generic Subdomains may contain distinct models and BCs seem ideal solution to separate those generic models?!
3)
Could you also help me with the following question, since it's confusing me quite a bit: if generic element ( such as Time, Currency and Money ) is also used by Core Domain, then only implementation option is Shared Kernel ( ie this generic element is shared by both Core Domain and any other subdomain(s) that needs it ), but if generic element is used only by Core Domain, then we shouldn't bother with Shared Kernel, but should instead define this generic element directly within Core Domain ?
thank you
1a) In that quote the author is referring to the entire domain, not the core domain. The entire domain can span multiple BCs. The relationship between a BC and core domain can be more complicated. Domains, sub-domains and the core domain are elements of the problem space. A BC is an artifact of the solution space. In reality, they may not always be one-to-one, however that is the ideal.
1b) One should certainly have an idea of what the core domain is when defining BCs. As stated, ideally, they should be one-one. However, a BC may be defined to fulfill needs of of a system in a non-ideal state.
1c) A domain spans multiple BCs but despite explicit boundaries, domain behavior can certainly span BCs. A context map can describe such cross-BC interactions. The quote itself is based around the idea of a domain vision statement the purpose of which is to highlight the value of the core domain and possibly explain the relationship to BCs.
2) Multiple BCs can make use of a single generic sub-domain. I would avoid the term "spans" here because that overemphasizes the importance of the generic sub-domain for the entire domain model.
UPDATE
1b) It may be that a core-domain is implemented with multiple bounded contexts. This isn't necessarily a defect and in some instances is the ideal. It may also be that a single BC contains multiple sub-domains. This is usually not ideal because it likely indicates a conflated BC.
1c) By definition BCs are physically partitioned and shouldn't have direct dependencies. I think this is what the author is referring to. The issue he's highlighting is that you can have multiple BCs at play which warrants explanation, especially when a single sub-domain is addressed.
2a) A signle GS can be used by multiple BCs. This is so because the sub-domain is generic. So the GS doesn't contain the BCs; instead, it is referenced by the BCs.
2b) Having a generic sub-domain "span" the system may be an indication that it isn't really a generic sub-domain, but a core domain. This is not to say that a generic component can't be used throughout the system, quite the contrary. However in that case, the component spanning the system is only a technical axis.
UPDATE 2
1b) Yes a sub-domain is a cohesive component of the entire domain. A sub-domain can span multiple BCs. This can be acceptable because a BC is a solution space artifact and there can be technical reasons or even organizational issues for its existence. For example, in the domain of an online retailer there is a product catalog sub-domain. This would have a corresponding products BC. However, additional functionality regarding product search can be placed into a product search BC. This is still part of the catalog sub-domain, but a new BC for technical reasons. On the other hand, when a single BC contains multiple sub-domains, this can be problematic.
2a) I think I got overly semantic on the use of the word span. A generic sub-domain can be a BC. However, care must be taken to ensure that a generic sub-domain is in fact used in a generic way.
3) Yes. Beyond that, base classes like Money can be implemented uniquely for each sub-domain even if they are used in multiple places. Sometimes copy-and-paste is the best pattern.
1a) Yes, the Core Domain essentially is the set of bounded contexts that worth the application's development from the customer point of view.
1b) No, some generic elements often play a key role in the Core Domain. See for example Time, Currency and Money that are present in many Shared Kernel: they are really generic but important to the Core Domain rules.
1c) Context boundaries are defined after terms' semantics. In a BC, no term should mean more than one thing (see also SRP). They are almost linguistic boundaries! When you see that a class has more than one meaning in the domain expert's mind, you know that you have mixed different BC.
2) Yes, Generic Subdomains are those part of the domain model (or, the set of the bounded contexts) that are useful but not central in the application. I've built several applications with generic subdomains: when they add some value that the customer wish to pay (and I can't provide such value with a simple CRUD component).
Note that what's "Core Domain" in your application is a qualitative definition: I've seen many times secondary parts of successful applications to achieve importance when the customer's corporate organization changed. Thus, what is Core Domain today might be not tomorrow.
When you are developing an architecture in OO/DDD style and modeling some domain entity e.g. Order entity you are putting whole logic related to order into Order entity.
But when the application becomes more complicated, Order entity collects more and more logic and this class becomes really huge.
Comparing with anemic model, yes its obviously an anti-pattern, but all that huge logic is separated in different services.
Is it ok to deal with huge domain entities or i understand something wrong?
When you are trying to create rich domain models, focus entities on identity and lifecyle, and thus try to avoid them becoming bloated with either properties or behavior.
Domain services potentially are a place to put behavior, but I tend to see a lot of domain service methods with behavior that would be better assigned to value objects, so I wouldn't start refactoring by moving the behavior to domain services. Domain services tend to work best as straightforward facades/adaptors in front of connections to things outside of the current domain model (i.e. masking infrastructure concerns).
You can also put behavior in Application services, but ask yourself whether that behavior belongs outside of the domain model or not. As a general rule, try to focus application services more on orchestration-style tasks that cross entities, domain services, repositories.
When you encounter a bloated entity then the first thing to do is look for sets of cohesive set of entity properties and related behavior, and make these implicit concepts explicit by extracting them into value objects. The entity can then delegate its behavior to these value objects.
Since we all tend to be more comfortable with entities, try to be more biased towards value objects so that you get the benefits of immutability, encapsulation and composability that value objects provide - moving you towards a more supple design.
Value objects enable you to incorporate a more functional style (eg. side-effect-free functions) into your domain model and thus free up your entities from having to deal with the complexity of adding complicated behavior to the burden of managing identity and lifecycle. See the pattern summaries for entities and value objects in Eric Evan's http://domainlanguage.com/ddd/patterns/ and the Blue Book for more details.
When you are developing an architecture in OO/DDD style and modeling
some domain entity e.g. Order entity you are putting whole logic
related to order into Order entity. But when the application becomes
more complicated, Order entity collects more and more logic and this
class becomes really huge.
Classes that have a tendency to become huge, are often the classes with overlapping responsibilities. Order is a typical example of a class that could have multiple responsibilities and that could play different roles in your application.
Given the context the Order appears in, it might be an Entity with mutable state (i.e. if you're managing Order's commercial condition, during a negotiation phase) but if you're application is managing logistics, an Order might play a different role: and an immutable Value Object might be the best implementation in the logistic context.
Comparing with anemic model, yes its
obviously an anti-pattern, but all that huge logic is separated in
different services.
...and separation is a good thing. :-)
I have got a feeling that the original model is probably data-centric and data serving different purposes (order creation, payment, order fulfillment, order delivery) is piled up in the same container (the Order class). Can't really say it from here, but it's a very frequent pattern. Not all of this data is useful for the same purpose at the same time.
Often, a bloated class like the one you're describing is a smell of a missing separation between Bounded Contexts, and/or an incomplete Aggregate separation within the same bounded context. I'd have a look to:
things that change together;
things that change for the same reason;
information needed to fulfill behavior;
and try to re-define aggregate boundaries accordingly. And also to:
different purposes for the application;
different stakeholders;
different implicit models/languages;
when it comes to discover the involved contexts.
In a large application you might have more than one model, thus leading to more than a single representation of a single domain concept, at least for concepts that are playing many roles.
This is complementary to Paul's approach.
It's fine to use services in DDD. You will commonly see services at the Domain, Application or Infrastructure layers.
Eric uses these guidelines in his book for spotting when to use services:
The operation relates to a domain concept that is not a natural part of an ENTITY or VALUE OBJECT.
The interface is defined in terms of other elements in the domain model
The operation is stateless
What are DDD recommendations for inter-domain referencing design?
Should I try to connect them as "Matryoshka" (put one into another) or it is better to create upper-level "inter-domain" business service?
P.S. Crossing this smooth water, I was unable to find anything useful to read in the Internet, and have started thinking that for this kind of things exist better term than "inter-domain referencing"... Am I right?
DETAILS:
I have two models/business services.
Semantically first domain (A) is CRM with sell/maintenance process for our goods, second domain (B) is "design" data of our goods. We have two view points on our goods: from seller perspective and from engineer perspective.
Actually each model is effective ORM (Object-Relational Mapping) tool to the same database.
There are some inter-domain activities e.g. validations (e.g. sometimes we can sell things to smb. only if some engineering rules are valid).
From developer's point of view I have two clear possibilities (reference B in A or create new cross reference domain/service C ). But from designer perspective I am lost in understanding what kind of Business Service I have when I compose business logic from two different domains.
As far as I know, DDD has no strict rules for 'inter-domain' referencing. At the end of the day your domain model will have to reference basic Java or .NET classes. Or it may reference specialized date/time or graph library (aka 'Generic Domain').
On the other hand DDD has a concept of Bounded Context. And it has quite a few patterns that can be applied when you work at the boundaries of the system. For example 'Anticorruption Layer' can be used to isolate you from legacy system. Other integration styles can be used depending on how much control you have over external code, team capabilities etc.
So there is probably no need to introduce artificial glue layer if you just dealing with two subdomains in one Bounded Context. Might also be worth reading Part 4 of DDD book (Strategic Design).
UPDATE:
Based on the information you provided, it looks like you only have one Bounded Context. You don't seem to have 'linguistic clashes' where the same word have two different meanings. Bounded Context integration patterns are most likely not applicable to your situation. Your Sales domain can reference Products domain directly. If you think of Products domain being more low-level and Sales being high level you can use Dependency Inversion Principle. Define an interface like ProductCompatiblityValidator in Sales and implement it in Products domain. And then inject the actual implementation at the application layer. This way you will not have a direct reference from Sales to Products.
In addition to what Dmitry has already said...
I think of any code that crosses bounded contexts as application layer code. I would have that application layer code reference domain types from both contexts (and their repositories) but not have two domains reference each other. I think it's OK to have business logic in an application layer if it specifically crosses domain boundaries and is unit-testable.
If you really have a hierarchy, then it would be OK to have the the more concrete subdomain reference the more abstract domain. However, I would be careful if this causes you to need to have domain objects reference repositories of any type. Pulling objects out of of a repository is rarely a true domain concept. Referencing repositories is best done in an application layer that sits a layer above the domain model.
Of course this is all as much art as science. I'd try modeling a thin slice of your application a couple different ways and see what friction you run into with each approach.
After reading Evan's and Nilsson's books I am still not sure how to manage Data access in a domain driven project. Should the CRUD methods be part of the repositories, i.e. OrderRepository.GetOrdersByCustomer(customer) or should they be part of the entities: Customer.GetOrders(). The latter approach seems more OO, but it will distribute Data Access for a single entity type among multiple objects, i.e. Customer.GetOrders(), Invoice.GetOrders(), ShipmentBatch.GetOrders() ,etc. What about Inserting and updating?
CRUD-ish methods should be part of the Repository...ish. But I think you should ask why you have a bunch of CRUD methods. What do they really do? What are they really for? If you actually call out the data access patterns your application uses I think it makes the repository a lot more useful and keeps you from having to do shotgun surgery when certain types of changes happen to your domain.
CustomerRepo.GetThoseWhoHaventPaidTheirBill()
// or
GetCustomer(new HaventPaidBillSpecification())
// is better than
foreach (var customer in GetCustomer()) {
/* logic leaking all over the floor */
}
"Save" type methods should also be part of the repository.
If you have aggregate roots, this keeps you from having a Repository explosion, or having logic spread out all over: You don't have 4 x # of entities data access patterns, just the ones you actually use on the aggregate roots.
That's my $.02.
DDD usually prefers the repository pattern over the active record pattern you hint at with Customer.Save.
One downside in the Active Record model is that it pretty much presumes a single persistence model, barring some particularly intrusive code (in most languages).
The repository interface is defined in the domain layer, but doesn't know whether your data is stored in a database or not. With the repository pattern, I can create an InMemoryRepository so that I can test domain logic in isolation, and use dependency injection in the application to have the service layer instantiate a SqlRepository, for example.
To many people, having a special repository just for testing sounds goofy, but if you use the repository model, you may find that you don't really need a database for your particular application; sometimes a simple FileRepository will do the trick. Wedding to yourself to a database before you know you need it is potentially limiting. Even if a database is necessary, it's a lot faster to run tests against an InMemoryRepository.
If you don't have much in the way of domain logic, you probably don't need DDD. ActiveRecord is quite suitable for a lot of problems, especially if you have mostly data and just a little bit of logic.
Let's step back for a second. Evans recommends that repositories return aggregate roots and not just entities. So assuming that your Customer is an aggregate root that includes Orders, then when you fetched the customer from its repository, the orders came along with it. You would access the orders by navigating the relationship from Customer to Orders.
customer.Orders;
So to answer your question, CRUD operations are present on aggregate root repositories.
CustomerRepository.Add(customer);
CustomerRepository.Get(customerID);
CustomerRepository.Save(customer);
CustomerRepository.Delete(customer);
I've done it both ways you are talking about, My preferred approach now is the persistent ignorant (or PONO -- Plain Ole' .Net Object) method where your domain classes are only worried about being domain classes. They do not know anything about how they are persisted or even if they are persisted. Of course you have to be pragmatic about this at times and allow for things such as an Id (but even then I just use a layer super type which has the Id so I can have a single point where things like default value live)
The main reason for this is that I strive to follow the principle of Single Responsibility. By following this principle I've found my code much more testable and maintainable. It's also much easier to make changes when they are needed since I only have one thing to think about.
One thing to be watchful of is the method bloat that repositories can suffer from. GetOrderbyCustomer.. GetAllOrders.. GetOrders30DaysOld.. etc etc. One good solution to this problem is to look at the Query Object pattern. And then your repositories can just take in a query object to execute.
I'd also strongly recommend looking into something like NHibernate. It includes a lot of the concepts that make Repositories so useful (Identity Map, Cache, Query objects..)
Even in a DDD, I would keep Data Access classes and routines separate from Entities.
Reasons are,
Testability improves
Separation of concerns and Modular design
More maintainable in the long run, as you add entities, routines
I am no expert, just my opinion.
The annoying thing with Nilsson's Applying DDD&P is that he always starts with "I wouldn't do that in a real-world-application but..." and then his example follows. Back to the topic: I think OrderRepository.GetOrdersByCustomer(customer) is the way to go, but there is also a discussion on the ALT.Net Mailing list (http://tech.groups.yahoo.com/group/altdotnet/) about DDD.