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.
Related
I am studying hard DDD now. After months of studying, I found a contradiction between modeling and coding. As you know, DDD has the principle of "Domain 1st, Tech 2nd". However, there are "definite" constraints when moving the actual model into the implementation, for example:
Original model:
With the domain concept, posts are associated with multiple comments, and comments are an ordinary model that depends on the post. Moving this into code ...
class Post{
Integer postId;
String title;
String content;
String writer;
Collection<Comment> comments;
}
class Comment{
String content;
}
Like this... But if there are hundreds of millions of comments, there will be performance problems. According to the solution I have investigated, finally I change the original model as follows....
Revised model:
Also the code will change...
class Post{
Integer postId;
String title;
String content;
String writer;
}
class Comment{
Integer postId;
String content;
}
This revised model works well for me and I am satisfied with the solution. But I feel something inconsistent. It seems that the model is distorting due to technical constraints. If we show the first and second models to the domain experts and talk about the diagram, he or she will better understand the first model.
Am I misunderstanding about DDD concept? If so, give me some advice. Thank you.
One of the changes in mindset that come with Domain Driven Design is that your domain will constantly evolve with changes to your understanding of the domain. It is not just that the domain will evolve, but your understanding and perception about it will evolve, as well.
What you are running into right now, in my opinion, is trying to rationalize the design based on the loading of one or more entities into an aggregate by looking at it from how it is persisted. This common parent and child relationship feels natural, because it is the way that most of us have done things in the past. Even from a DDD perspective, it is easy to get caught up in the "Comments can't exist without Posts" paradigm.
This comes down to the fact that you are modelling based upon data inside of the domain, instead of use cases. Look at it this way... Posts are not simply a collection of Comments. Instead, a Comment refers to a specific Post. The nuance sounds minor, but it has broad-reaching consequences. When modeled in this fashion, it matches your revised model - and it is completely and totally fine. The only thing you need to change is your mindset, being that Comment can be considered an Aggregate, just as a Post is. They both are going to have use cases where the other one must exist, but at the same time, you need to see that you are unlikely to do something where both are impacted as part of the same use case (outside of deletion of the Post).
To illustrate, consider this use case:
As a Writer, I want to be able to edit the Content of my Post.
Your new model actually effectively supports that. Instead of looking at the relationship, you are looking at how the domain is used. Should you load Comments for a Writer to edit? Without knowing your domain, I would still assume that you would not want to do so. There are use cases that will likely involve both Posts and Comments, and that is also fine. Since you have two Aggregates inside of a single Bounded Context, you will be able to support use cases that are solely based on Posts, solely based on Comments, or a combination of both.
In terms of the technical concerns, you mention "hundreds of millions of comments". I assume that you mean system-wide, and not for a single Post? Assume that you have an active post, and that it sees 20k comments in its lifetime. For a properly designed and optimized database, this should still not be an issue. When it becomes an issue, if it ever does, it can be further addressed by additional changes to the technology used, as opposed to changing the domain. You can look at things like caching strategies (outside of the domain, since that is an application concern and not a domain concern), external indexes, eventual consistency, etc.
Highly recommend taking a read through Vaughn Vernon's "Effective Aggregate Design" series of articles, if you have not already:
Effective Aggregate Design
Additionally, his excellent book "Implementing Domain-Driven Design", is a must-read, in my opinion. While the Evans material is essential, it is more like the theoretical concepts; whereas the Vernon material talks about how to put the concepts into practice and what the implications of those decisions are.
As an addendum, like plalx points out in the comments below. None of this is meant to be a generalization about Posts and Comments in general, but explicitly how they apply to your domain, as it has been described to us and what could be inferred from your models. Posts and Comments will likely behave differently for others, because others will have distinct use cases. Even within your own domain, should Posts and/or Comments exist in a different context, they could behave differently. Above all else, try and make sure that everything you add to your domain model (in general) is added because of a specific and direct use case. It is tempting to simply start data modeling, but you will start to find yourself trying to force use cases into the domain model. Domain modeling should not be a finite process, or a single step in the process. Be willing and able to adapt to changes in understanding or changes to the way that the business changes its overall operational strategies over time.
One pitfall I notice about people entering the DDD world is that they visualize their ARs as source of READ operations as well. So, many times they tend to "model" the ARs and its entities/value objects in a way that "appeals" a DTO that is meant to hydrate the UI.
In your case, I would make Post an AR and Comments another AR. Adding a comment shouldn't require to instantiate Post at all. Editing a Post shouldn't require to 'load' the comments at all.
Use an independent mechanism to project your post/comments into a POCO/DTO class that may make sense to have a collection of comments in your post.
Does it make sense?
I have a web application with news posts. Those news posts should be searchable. In context of DDD what kind of buililng block are search query and search result?
These are my thoughts
They both don't have identity, therefore they are not Entities. But the absence of identity doesn't imply they are Value Object. As Eric Evans states:
However, if we think of this category of object as just the absence of identity, we haven't added much to our toolbox or vocabulary. In fact, these objects have characteristics of their own and their own significance to the model. These are the objects that describe things.
I would like to say that both are value objects, but I'm not sure. What confuses me are examples that I've found on Internet. Usualy value object are part of other entities, they are not "standalone". Martin Fowler gives for example Money or date range object. Adam Bien event compares them to enums.
If search result would be considered value object, that would be value object that consists of entities. I'm not sure that's completely alright.
I don't think they are DataTransferObject. Because we are not current concerned with transferring data between layers, but we are concerned with their meaning for the model in absence of layer.
I don't think search query is command. Because it's not a request for change.
As stated on CQRS
People request changes to the domain by sending commands.
I'm trying to use and learn DDD, can someone clarify this problem to me? Where did I go wrong with reasoning?
The simple answer is that querying is probably not part of your domain. The domain model is not there to serve queries, it is there to enforce invariants in your domain. Since by nature queries are read-only, there are no invariants to enforce, so why complicate things? I think where people usually go wrong with DDD is that they assume since they are "doing DDD" every aspect of the system must be handled by a domain model. DDD is there to help with the complex business rules and should only be applied when/where you actually have them. Also, you can and probably should have many models to support each bounded context. But that's another discussion.
It's interesting that you mention CQRS because what does that stand for? Command query responsibility segregation. So if commands use the domain model, and query responsibility is segregated from that, what does that tell you to do? The answer is, do whatever is easiest to query and display that data. If select * from news table filled to dataset works, go with that. If you prefer entity framework, go with that. There is no need to get the domain model involved for queries.
One last point I'd like to make is I think a lot of people struggle with DDD by applying it to situations where there aren't many business invariants to enforce and the domain model ends up looking a lot like the database. Be sure you are using the right tool for the job and not over complicating things. Also, you should only apply DDD in the areas of your system where these invariants exist. It's not an all or nothing scenario.
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
Say I have a model Exam. There will be a collection of Question objects containing questions and answers, and a collection of what each student have answered.
I think it is ok for the application layer to give the presentation layer only the bits it need to create the UI. In other words when students are answering questions, the application layer does not present the other students to the presentation layer.
Same idea when the data goes back to the application layer. Questions cannot change, so we send only the students answer back to be attached to the domain model.
IMHO this is according to E. Evans description of the application layer: Defines the jobs the software is supposed to do and directs the expressive domain objects to work out problems.
Yes, it does make sense. Not only that, in most scenarios this should be the go-to architecture, in my opinion. The thing is DDD is great in managing complexity while keeping consistency within aggregates and bounded context - the things that occur when something gets changed. And there shouldn't be any change while reading (displaying) the data, so you get no help from DDD on this part. Moreover, if you use your domain object for providing data to your UI layer, you end up tailoring domain for user interface instead of business domain, and these are different contexts.
Actually there are entire architectures basing on that facts, CQRS being one of them. CQRS has this great idea of keeping two sets of data stores - one tailored to domain model, the other explicitly prepared for reading the data to present on UI (for example).
You might also be interested in this blog post on the repository pattern by Szymon Pobiega - it also follows the idea of separating the write (domain) and read (queries) side.
I am quite new with DDD and would like to know about any pitfalls you might want to share. I will summarize it later for more newbies to read :)
Thanks
Summary so far:
Anemic domain model where your entities are primarily only data bearing and contain no business logic
Not using bounded contexts enough
Focusing too much on patterns
There is a good presentation on this topic as well here (video).
Probably the most important one: not grokking the central, fundamental principle of the Domain Model and its representation in Ubiquitous Language. With the plethora of technology options around, it's very easy for your head to fill up with ORMs, MVC frameworks, ajax, sql vs nosql, ... So much so there's little space left for the actual problem you're trying to solve.
And that's DDD's key message: don't. Instead, explicitly focus on the problem space first and foremost. Build a domain model shorn of architectural clutter that captures, exposes and communicates the domain.
Oh, and another one: thinking you need Domain Services for everything you can do in the domain model. No. You should always first try to put domain logic with the Entity/Value type it belongs to. You should only create domain services when you find functions that don't naturally belong with an E/V. Otherwise you end up with the anaemic domain model highlighted elsewhere.
hth.
One of the biggest pitfalls is that you end up with a so-called anemic model where your entities are primarily only data bearing and contain no business logic. This situation often arises when you build your domain model on top of an existing relational data model and just make each table in the database an entity in your domain model.
You might enjoy presentation of Greg Young about why DDD fails.
In short:
Lack of intent
Anemic Domain Model
DDD-Lite
Lack of isolation
Ubiquitous what?
Lack of refinement
Proxy Domain Expert (Business analyst)
Not using bounded contexts enough. It's toward the back of the the big blue book but Eric Evans has gone on record as saying that he believes that bounded contexts and ubiquitous language are THE most important concepts.
Similarly, people tend to focus too much on the patterns. Those aren't the meat of DDD.
Also, if you do not have a lot of access to domain experts you are probably not doing DDD, at best you are DDDish.
More concretely, if you end up with many-to-many relationships, you've probably designed something wrong and need to re-evaluate your aggregate roots/contexts
Only adding to what others have already said;
My personal experience is that people often end up with an anemic model and a single model instead of multiple context specific models.
Another problem is that many focus more on the infrastructure and patterns used in DDD.
Just because you have entities and repositoriesand are using (n)Hibernate it doesn't mean you are doing DDD.
It's not from my personal experience with subject, but it was mentioned for a couple of times in DDD books and it's what I've been thinking about recently: use Entities when you really need identity, in other cases use Value Object. I.e., Entity pattern often happens to be the default choice for any model noun, and it's not the way it should be.
Beware of the Big Ball of Mud.
One of the pitfalls of domain driven design is to introduce ambiguity into a model. As explained in the article Strategic Domain Driven Design with Context Mapping:
Ambiguity is the super-villain of our
Ubiquitous Language
This may happen when two distinct concepts share the same name, or when the same concept can have different uses. It may be necessary to
expose the domain structure in
terms of bounded contexts in a context
map
If a model is used in too many different ways, or has too many responsibilities, it may be a sign that it should be divided.