Currently, my service layer handles loading aggregate roots that are responsible to react to some domain events. This involves calling the persistence layer to filter and load the responsible aggregate roots using some domain knowledge (who should/when to react). Is this considered domain knowledge leakage and how to prevent it?
Thank you!
my service layer handles loading aggregate roots that are responsible to react to some domain events. This involves calling the persistence layer to filter and load the responsible aggregate roots using some domain knowledge (who should/when to react).
If you are willing to substitute "application layer" for "service layer", I think you'll find that's a pretty good match for the patterns that Eric Evans describes in the original Domain Driven Design book.
This layer is kept thin. It does not contain business rules or knowledge, but only coordinates tasks and delegates work to collaborations of domain objects in the next layer down. It does not have state reflecting the business situation, but it can have state that reflects the progress of a task for the user or the program.
The sample cargo shipping application (a collaboration between Eric Evans and Citerus) exhibits patterns that I see fairly often when discussing designs with other DDD practitioners. The code I think you are talking about is here: https://github.com/citerus/dddsample-core/blob/master/src/main/java/se/citerus/dddsample/application/impl/BookingServiceImpl.java
public void assignCargoToRoute(final Itinerary itinerary, final TrackingId trackingId) {
final Cargo cargo = cargoRepository.find(trackingId);
if (cargo == null) {
throw new IllegalArgumentException("Can't assign itinerary to non-existing cargo " + trackingId);
}
cargo.assignToRoute(itinerary);
cargoRepository.store(cargo);
logger.info("Assigned cargo " + trackingId + " to new route");
}
In this case, Itinerary and TrackingId are value objects - the definitions are in the domain layer, but these instances are actually constructed in the web/presentation layer, and passed to the application logic that is responsible for coordination.
I am wondering how to go about loading/filtering the responsible aggregate roots without leaking domain knowledge to service layer? For example, filtering aggregate roots using some business knowledge about who/when should a domain event be handled.
The heuristic I use is that we want to separate calculation/logic from information retrieval. So if identifying the right aggregate to load depends on the form data submitted by the user, a tax table, and the conversation the CEO had at the airport last week, then we'd prefer a design like
aggregateId = computeTheAggregateId(formData, taxTable, ceo.conversation())
aggregate = repository.get(aggregateId)
aggregate.doSomethingCool(formData)
Does computeTheAggregateId belong in application or in domain? In the abstract, it's not obvious that it matters very much. The right answer might depend on how often it changes, or what code changes at the same time.
Ultimately: this is a pattern language - if the pattern doesn't "work" in the context you are in, then you are expected to have the good judgment not to use it.
Related
I thinking about modeling aggregates, invariants, data etc. There is common advice to design aggregates to be small. I have problem a with correct splitting domain and simple CRUD.
Let's assume that we have application where we are able to create project and join to it collaborators. There are a lot of informations related with project at the stage of creating (name, description, project_aims, notes, creation date, modified date, collaborators). How to correct design aggregate where there is a rule which check that we can only add 5 collaborators. Taking into consideration that fields name, description, project_aims, notes doesn't really take part in any business rule and there is only requirements that this fields should'nt be empty (those are really invariants?) should those fields really be a part of aggregate?
Is'nt that our real Domain (aggregates, entities, value objects, policies) should hold only data which take part with protecting invariants or help making business decisions?
If so, how to (create) project described above? Should class with all that nonsignificant (from a business point of view) fields be implemented as anemic model outside the Domain and Aggregate root should just have method addCollaborator which protect quantity of collaborators? Is it good idea to save anemic class object using Dao (operates on db table) and for Domain implementation of aggregate, create Repository?
How to add first collaborator during creating project as at the beggining we create anemic class object outside Domain?
Thank you for any help and advice
Papub
"How to correct design aggregate where there is a rule which check that we can only add 5 collaborators"
Project AR most likely maintains a set of collaborators and throws whenever it's size would exceed 5.
"there is only requirements that this fields should'nt be empty (those are really invariants?)"
Yes, these may be simple rules, but are still are invariants.
"should hold only data which take part with protecting invariants or help making business decisions"
This can be done when modeling ARs with EventSourcing, where you'd only materialize the properties needed to check invariants on the AR, while having all data in the full set of events.
"implemented as anemic model outside the Domain and Aggregate root should just have method addCollaborator which protect quantity of collaborators".
You could always attempt to mix CRUD-driven anemia with rich always-valid models, but the anemic/rich model decision is usually consistent for a given Bounded Context (BC), meaning you may have CRUDDy BCs and rich domain model BCs, but rarely both strategies in the same BC.
For instance, perhaps "Project Definition" is a CRUD-driven BC while "Collaboration" isin't. Those BCs may not make any sense, but it's just to give an example.
Furthermore, don't forget DDD tactical patterns are there to allow manage the complexity, they aren't hard rules. If handling a part of your AR through services and another (where there's more meat) with rich behaviors then perhaps that's acceptable. Still, I'd probably prefer CRUDDy behaviors on the ARs themselves like an update method rather than giving up in the anemic direction.
Is it ok for my aggregate root to act as a factory for entities that he manages?
E.G: is it ok for my aggregate root "Question" to instantiate a entity "Answer"?
Is it ok for my aggregate root to act as a factory for entities that he manages?
Almost.
The aggregate root isn't an entity as such, but a role played by an entity. Think interface - it gives the application a restricted access to the domain model, encapsulating the actual implementation.
It's natural to have the aggregate be responsible for its own state; after all, all of the components of the aggregate are going to be drawn from the same data model (they are persisted together).
Within your entity (which is acting as the aggregate root), you want your code to align as closely as possible with the language of the domain. That will usually mean that you don't have a "factory", as in the design pattern, but instead have some entity in the model that produces the managed entities.
Udi Dahan touched on this, somewhat obliquely, when he wrote Don't Create Aggregate Roots.
Customers don’t just appear out of thin air.
The entities in your model all come from other entities in your model. Turtles all the way down.
So introducing the factory design pattern into the domain language is a bit sketch.
Because the domain model lives in memory... because its unusual for the domain model to have side effects... a lot of the usual motivations for abstracting connection points don't apply. If you find yourself, for example, wanting to inject a mock into your domain model for unit testing, then something has gone badly wrong (into domain services, yes, but not into entities).
Yes, it is, if the code is a simple new Answer (someArguments, ...).
If it is a more complicated process then you should extract this code into a AnswerFactory class.
EDIT:
The desire to create a clean code dictates this and not DDD. A rule from DDD that is relevant to your question is that Domain (so all classes from the Domain layer) should not depend on any other layers (like Infrastructure or Application).
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
I read this article today and am trying to clarify some things. Does this article mean that model objects should contain business logic?
For example let us say that there is a Student object that we retrieve form the database via Hibernate. Does this article say that the Student object should contain business logic as well rather than having only getters and setters?
Disregard the date, what Martin Fowler states is as relevant today as it was eight years ago. Fowler does not state that you should mix persistence into the domain objects, quite the contrary:
"It's also worth emphasizing that putting behavior into the domain objects should not contradict the solid approach of using layering to separate domain logic from such things as persistence and presentation responsibilities."
You should read the article again, because the article describes this anti-pattern extermely well, but I shall try to summarize it for you in the context of what you are asking:
If you are to create a domain model, yes your domain objects should contain business logic as well as state, and changes to the state of your domain entities should be done through methods which convey business meaning. The anemic domain model is an anti-pattern because you incur the cost of an extra layer of classes but you are not reaping the benefits. Why bother with a domain layer which you have to map against the database when it convey exactly the same intent as you get from using an active record style approach (dataset, etc)? So the article does not say that you should have a "student-object", but it states that if you do, you should definitively add state to that class.
The point in the article about not having a set of objects to represent your model if you don't also model your domain can be a bit confusing due to the technologies available today. There are great tools out there which can effortlessly move data between a set of POCOs and the database (Nhibernate, EF, Simple Data, Massive, Dapper, etc) so in that retrospectiv I would say that you would probably end up with a set of "entities" in most solutions today, the real difference being whether this is just a database model or a real domain model.
I'll close up by showing you an example of the interaction between a domain entry point (command handler) and a domain model. The method shown below lives in a command handler which consumes a request to change something in the domain. Notice that the layer-ontop-of-your-domain-code simply gets the domain entity and calls one method on the domain? Thats an important point because the workflow we are modelling is fully encapsulated in the domain, not in the layer-ontop-of-your-domain-code or anywhere else:
public void Handle(AddEmailAddressForAlerts command)
{
var agent = _repository.GetAgent(command.AgentKey.AgentId);
agent.AddEmailAddressForAlerts(new EmailAddress(command.EmailAddress));
}
Notice the date - the citation is over eight years old.
Martin Fowler is obviously a very smart guy, and I like the article's point, but take it with a grain of salt. Encapsulating state and behavior together is a good thing in general, but it should be balanced against layering considerations. Persistence isn't the same thing as business logic. I'd still have a separate persistence tier; I wouldn't put persistence in a model object.
Dogma should be challenged in all its forms. Be aware of other people's ideas, but think for yourself.
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.