I am new to DDD design concepts but I'd like to clarify something as I read articles about it. Jimmy Boggard use the following words:
"Nothing outside the Aggregate boundary can hold a reference to anything inside, except to the root Entity.", "Only Aggregate Roots can be obtained directly with database queries. Everything else must be done through traversal."
Let's say I want to delete a review of a post. Here as far as I understood, post is root. So all the communication with a review should be made through post object.
That means I need to get both the id of aggregate root and the id of the aggregate entity as parameters of an HTTP delete request?
That means I need to get both the id of aggregate root and the id of the aggregate entity as parameters of an HTTP delete request?
Short answer: yes.
Somewhat longer answer: in order to interact with an entity that is subordinate to an aggregate root, you need to route to the root (so you need the Id), and you need to pass to the root as arguments the information needed to specify the target entity.
DELETE doesn't support a request body; so the arguments need to be something that the origin server can recover from the URI alone (either the arguments are encoded into the URI, or the URI gives you access to a resource that knows what the arguments are).
Note: it's not immediately obvious that Review should be a subordinate entity in the Post aggregate. Aggregate design is about behaviors not relations. If modeling Review as a separate aggregate from Post makes your life easier, you should consider it.
It would be more practical to do so but you don't absolutely have to. Your REST API doesn't have to be an exact reflection of your domain model - HTTP and DDD are two very different paradigms with their own constraints and view of the world.
A valid alternative would be to retrieve the correct Post based solely on the ReviewId and ask that Post to delete the Review
DELETE /reviews/1234
...
post = postRepository.getPostForReview(reviewId);
post.deleteReview(reviewId);
though I agree that in this particular instance, DELETE /posts/1234/reviews/5678 is probably a better URI.
Related
I've been getting acquainted with DDD and trying to understand the way Entities and Aggregate Roots interact.
Below is the example of the situation:
Let's say there is a user and he/she has multiple email addresses (can have up to 200 for the sake of example). Each email address has it's own identity and so does the user. And there is one to many relationship between users and their email.
From the above example I consider Users and Emails as two entities while Users is the aggregate root
DDD Rules that I came across:
Rule: Only aggregate root has access to the repository.
Question 1: Does it mean that I cannot have a separate database table/collection to store the emails separately? Meaning that the emails have to be embedded inside the user document.
Rule: Entities outside the aggregate can only access other entities in the aggregate via the aggregate root.
Question 2: Now considering I do split them up into two different tables/collection and link the emails by having a field in email called associatedUserId that holds the reference to the user that email belongs to. I can't directly have an API endpoint like /users/{userId}/emails and handle it directly in the EmailService.getEmailsByUserId(String userId)? If not how do I model this?
I am sorry if the question seems a bit too naive but I can't seem to figure it out.
Only aggregate root has access to the repository
Does it mean that I cannot have a separate database table/collection to store the emails separately? Meaning that the emails have to be embedded inside the user document.
It means that there should be a single lock to acquire if you are going to make any changes to any of the member entities of the aggregate. That certainly means that the data representation of the aggregate is stored in a single database; but you could of course distribute the information across multiple tables in that database.
Back in 2003, using relational databases as the book of record was common; one to many relationships would normally involve multiple tables all within the same database.
Entities outside the aggregate can only access other entities in the aggregate via the aggregate root.
I can't directly have an API endpoint like /users/{userId}/emails and handle it directly in the EmailService.getEmailsByUserId(String userId)?
Of course you can; you'll do that by first loading the root entity of the User aggregate, then invoking methods on that entity to get at the information that you need.
A perspective: Evans was taking a position against the idea that the application should be able to manipulate arbitrary entities in the domain model directly. Instead, the application should only be allowed to the "root" entities in the domain model. The restriction, in effect, means that the application doesn't really need to understand the constraints that are shared by multiple entities.
Four or five years later cqrs appeared, further refining this idea -- it turns out that in read-only use cases, the domain model doesn't necessarily contribute very much; you don't need to worry about the invariants if they have already been satisfied and you aren't changing anything.
In effect, this suggests that GET /users/{userId}/emails can just pull the data out of a read-only view, without necessarily involving the domain model at all. But POST /users/{userId}/emails needs to demonstrate the original care (meaning, we need to modify the data via the domain model)
does this mean that I need to first go to the UserRepo and pull out the user and then pull out the emails, can't I just make a EmailService talking to an Email Repo directly
In the original text by Evans, repositories give access to root entities, rather than arbitrary entities. So if "email" is a an entity within the "user aggregate", then it normally wouldn't have a repository of its own.
Furthermore, if you find yourself fighting against that idea, it may be a "code smell" trying to bring you to recognize that your aggregate boundaries are in the wrong place. If email and user are in different aggregates, then of course you would use different repositories to get at them.
The trick is to recognize that aggregate design is a reflection of how we lock our data for modification, not how we link our data for reporting.
After reading Eric Evans' DDD, I'm trying to apply it to the project I'm managing. There are some user specific query data and I'm not really sure of how to implement this in a DDD way.
For example, if a user queries notices, the application should tell the user wether each post is read or not. Normally in such situations, I would respond with data that looks like following:
{
"notices": [
{"content": "foo", "is_read": true},
{"content": "bar", "is_read": false}
]
}
Suppose there is Notice entity and Read entity that saves wether a User has read it. Also assume that there are so many users reading the notice that retrieving all users for the is_read is not a efficient way.
Since Read entity is never queried without Notice entity, I could put it inside a Notice aggregate. Then implement query function taking the requesting user as parameter.
Or I could separate NoticeRepository and ReadRepository, query notices and then join them in the application layer with reads queried with notice ids.
The first option seems that it is assuming an user querying the notices and corrupting the domain layer with application logics. On the other hand, the second option gives me a feeling that I'm implementing a simple feature in an unnecessarily complicated way. And I cannot really think of other options right now.. What could be the best practice for such a case?
I cannot really think of other options right now
I can see two possible issues that could be tripping you up.
First, your domain model may be missing an important concept. How do we know if a Bob read a particular notification or not? There may be some entity in the domain, perhaps an Acknowledgement, that captures Bob, and the document that he read, and perhaps other information interesting to this domain (which version of the document did he read? When? What channel? when? and so on).
Thus, the view that would produce would look something like the list of active notifications left joined to the acknowledgements from Bob.
The other thing that could cross you up is that trying to do joins "by hand", using repositories to fetch data, is a real drag. Furthermore, what people have come to realize in the years since the blue book was written, it may not be necessary. Because queries are safe, they don't change the underlying data -- and if the underlying data isn't going to change, we don't really need a domain model to protect a business invariant.
This need to go all in a Query Service,
The book of Eric Evans is good basis and it has evolved to more modern patterns now, for instance CQRS in the book of Vaughn Vernon, Implementing Domain Driven Design (IDDD).
Your query service would be responsible of displaying a list of notices, updating a read column for this user in a separate table.
You might have a look at some example of query services (written in java) here:
https://github.com/VaughnVernon/IDDD_Samples/blob/master/iddd_collaboration/src/main/java/com/saasovation/collaboration/application/forum/ForumQueryService.java
https://github.com/VaughnVernon/IDDD_Samples/blob/master/iddd_collaboration/src/main/java/com/saasovation/collaboration/application/forum/DiscussionQueryService.java
I wouldn't have a Read entity. Just Notice and User. In User you would have a list of Notice ids that the user has read (or viceversa, in Notice you would have a list of the User ids who have read the Notice).
Then , to query the info you need to show in the user interface, you have several alternatives, as Vaughn Vernon says in his book Implementing DDD (page 512):
DTOs
Mediator
Domain Payload Object
State Representations
Use Case optimal repository queries (closed to CQRS)
Data Transformers
I am currently working on my first bigger DDD application. For now it works pretty well, but we are stuck with an issue since the early days that I cannot stop thinking about:
In some of our aggreagtes we keep references to another aggregate-root that is pretty essential for the whole application (based on their IDs, so there are no hard references - also the deletion is based on events/eventual consistency). Now when we create a new Entity "Entity1" we send a new CreateEntity1Command that contains the ID of the referenced aggregate-root.
Now how can I check if this referenced ID is a valid one? Right now we check it by reading from the other aggregate (without modifying anything there) - but this approach somehow feels dirty. I would like to just "trust" the commands, because the ID cannot be entered manually but must be selected. The problem is, that our application is a web-application and it is not really safe to trust the user input you get there (even though it is not accessibly by the public).
Did I overlook any possible solutions for this problems or should I just ignore the feeling that there needs to be a better solution?
Verifying that another referenced Aggregate exists is not the responsibility of an Aggregate. It would break the Single responsibility principle. When the CreateEntity1Command arrive at the Aggregate, it should be considered that the other referenced Aggregate is in a valid state, i.e. it exists.
Being outside the Aggregate's boundary, this checking is eventually consistent. This means that, even if it initially passes, it could become invalid after that (i.e. it is deleted, unpublished or any other invalid domain state). You need to ensure that:
the command is rejected, if the referenced Aggregate does not yet exists. You do this checking in the Application service that is responsible for the Use case, before dispatching the command to the Aggregate, using a Domain service.
if the referenced Aggregate enters an invalid state afterwards, the corrects actions are taken. You should do this inside a Saga/Process manager. If CQRS is used, you subscribe to the relevant events; if not, you use a cron. What is the correct action it depends on your domain but the main idea is that it should be modeled as a process.
So, long story short, the responsibilty of an Aggregate does not extend beyond its consistency boundary.
P.S. resist the temptation to inject services (Domain or not) into Aggregates (throught constructor or method arguments).
Direct Aggregate-to-Aggregate interaction is an anti-pattern in DDD. An aggregate A should not directly send a command or query to an aggregate B. Aggregates are strict consistency boundaries.
I can think of 2 solutions to your problem: Let's say you have 2 aggregate roots (AR) - A and B. Each AR has got a bunch of command handlers where each command raises 1 or more events. Your command handler in A depends on some data in B.
You can subscribe to the events raised by B and maintain the state of B in A. You can subscribe only to the events which dictate the validity.
You can have a completely independent service (S) coordinating between A and B. Instead of directly sending your request to A, send your request to S which would be responsible for a query from B (to check for validity of referenced ID) and then forward request to A. This is sometimes called a Process Manager (PM).
For Example in your case when you are creating a new Entity "Entity1", send this request to a PM whose job would be to validate if the data in your request is valid and then route your request to the aggregate responsible for creating "Entity1". Send a new CreateEntity1Command that contains the ID of the referenced aggregate-root to this PM which uses ID of the referenced AR to make sure it's valid and if it's valid then only it would pass your request forward.
Useful Links: http://microservices.io/patterns/data/saga.html
Did I overlook any possible solutions for this problems
You did. "Domain Services" give you a possible loop hole to play in.
Aggregates are consistency boundaries; their behaviors are constrained by
The current state of the aggregate
The arguments that they are passed.
If an aggregate needs to interact with something outside of its boundary, then you pass to the aggregate root a domain service to encapsulate that interaction. The aggregate, at its own discretion, can invoke methods provided by the domain service to achieve work.
Often, the domain service is just a wrapper around an application or infrastructure service. For instance, if the aggregate needed to know if some external data were available, then you could pass in a domain service that would support that query, checking against some cache of data.
But - here's the trick: you need to stay aware of the fact that data from outside of the aggregate boundary is necessarily stale. There might be another process changing the data even as you are querying a stale copy.
The problem is, that our application is a web-application and it is not really safe to trust the user input you get there (even though it is not accessibly by the public).
That's true, but it's not typically a domain problem. For instance, we might specify that an endpoint in our API requires a JSON representation of some command message -- but that doesn't mean that the domain model is responsible for taking a raw byte array and creating a DOM for it. The application layer would have that responsibility; the aggregate's responsibility is the domain concerns.
It can take some careful thinking to distinguish where the boundary between the different concerns is. Is this sequence of bytes a valid identifier for an aggregate? is clearly an application concerns. Is the other aggregate in a state that permits some behavior? is clearly a domain concern. Does the aggregate exist at all...? could go either way.
I have seen lot of discussions regarding this topic but i couldn't get a convincing answer. The general advice is not to have repository inside a domain object. What about an aggregate root? Isnt it right to give the root the responsibility to manipulate the composed objects?
For example, i have a microservice which takes care of invoices. Invoice is an aggregate root which has the different products. There is no requirement for this service to give details about individual products. I have 2 tables, one to store invoice details and other to store products of those invoices. I have two repositories corresponding to the tables. I have injected product repository inside the invoice domain object. Is it wrong to do so?
I see some mistakes according to DDD principles in your question. Let me try to clarify some concepts to give you hand.
First, you mentioned you have an Aggregate Root which is Invoice, and then two different repositories. Having an Aggregate Root means that any change on the Entities that the Aggregate consists of should be performed via the Aggregate Root. Why? That's because you need to satisfy some business rule (invariant) that applies on the relation of those Entities. For instance, given the next business rule:
Winning auction bids must always be placed before the auction ends. If a winning bid is placed after an auction ends, the domain is in an invalid state because an invariant has been broken and the model has failed to correctly apply domain rules.
Here there is an aggregate consisting of Auction and Bids where the Auction is the Aggregate Root.
If you have a BidsRepository, you could easily do:
var newBid = new Bid(money);
BidsRepository->save(newBid);
And you were saving a Bid without passing the defined business rule. However, having the repository just for the Aggregate Root you are enforcing your design because you need to do something like:
var newBid = new Bid(money);
auction.placeBid(newBid);
auctionRepository.save(auction);
Therefore, you can check your invariant within the method placeBid and nobody can skip it if they want to place a new Bid. Afterwards you can save the info into as many tables as you want, that is an implementation detail.
Second, you said if it's wrong injecting the repository into a Domain class. Here a quick explanation:
The repository should depend on the object it returns, not the other way around. The reason for this is that your "domain object" (more on that later) can exist (and should be testable) without being loaded or saved (that is, having a dependency on a repository).
Basically your design says that in order to have an invoice, you need to provide a MySQL/Mongo/XXX instance connection which is an infrastructure detail. Your domain should not know anything about how it is persisted. Your domain knows about the behavior like in the scenario of the Auction and Bids.
These concepts just help you to create code easier to maintain as well as help you to apply best practices such as SRP (Single Responsibility Principle).
Yes, I think it is wrong.
Domain should match real business model and should not care how data is persisted. Even if data internally are stored in multiple tables, this should not affect domain objects in any way.
When you are loading aggregate root, you should load related entities as well in one go. For example, this can easily be achieved with Include keyword in Entity Framework if you are on .NET. By loading all the data you ensure that you have full representation of business entity at any given time and you don't have to query database anymore.
Any changes in related entities should be persisted together with aggregate root in one atomic operation (usually using transactions).
I'm learning DDD and wanted to start modelling a fairly trivial example, a blog application.
One area I'm a little confused about is defining aggregate roots.
Here's my model so far:
Site
has many
Blog
has reference to Site
has many
Post
has reference to Blog
has Category
has many
Comments
In this example the only thing I am sure of is that Comment is a value object since it makes no sense outside the context of a post.
But then based on:
Only Aggregate Roots can be obtained directly with database queries.
Everything else must be done through traversal.
I would be inclined to make Site, Blog and Post ARs since I would want to obtain them all directly rather than traversing a collection.
I realize that a Blog isn't exactly a complex domain model so doesn't really warrant applying DDD but I just want to understand how these type of relationships are modelled.
It is not because you have a hierarchy that you must define an aggregate. The aggregate construct will come handy if you have invariant to maintain within the hierarchy.
In your example, assume that you want each post in a blog to have a unique 'slug' (Wordpress style, so that the title appears in the URL). Only the 'Blog' entity can enforce this invariant. Similarly, in that case it would make sense to make it the aggregate and have the post added via the blog entity.
Another example: your site can be public or private. This is an attribute of the Site entity. You must therefore make sure to access to a post using traversal from the aggregate root which would be the site since only the site can authorize you or not to access the underlying objects.
If you make the site the aggregate root, you could end up with an url like this:
http://site.com/myblog/apost
Your code would first retrieve the site entity, from that entity it gets the blog, and from the blog entity it fetch the post. How you go about retrieveing the child entities is up to you. This model does not force you to load all blog posts in memory when retrieving the site. It just force you to retrieve the blog from the site, and the posts from the blog.