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.
Related
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.
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 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.
I have a City aggregate, having a list of PointOfInterest entities. This latter entity lies logically inside the City aggregate for reasons that won't be explained here. No entity holds a link to PointOfInterest, apart from the aggregate root, City.
However, we have a web page for PointOfInterest, browsable from the City page, that (mainly for SEO reasons) only has the PointOfInterest id in its URL.
Thus, from the controller, it would be handy to query the CityRepository for a PointOfInterest directly, such as CityRepository.findPointOfInterestById().
The other option would be to query CityRepository.findCityByPointOfInterestId(), then City.findPointOfInterestById(), which looks a bit cumbersome in this case.
Is there anything wrong with the first approach?
Since PointOfInterest is part of the City aggregate, you have to accept that all references to PointOfInterests must be obtained by traversal of a City. It doesn't seem appropriate for CityRepository to expose GetPoI() methods because it would allow an outside object to get a direct reference to a PoI, defeating the whole purpose of an aggregate. Besides, it doesn't really seem like a natural responsibility of a CityRepository to deal with PoIs.
As Wouter points out, your feeling the need to do convoluted things like this might be a sign that the current design is not quite appropriate. If PointOfInterest turns out to be one of the major entities in your application and if the user can access it right from the start of his navigation without necessarily going through a City first, why not consider giving PoI its own aggregate ? As for the PoI / PoIType relationship, it seems more logical for a PoI to have a PoIType than the other way around.
I'm working a pretty standard e-commerce web site where there are Products and Categories. Each product has an associated category, which is a simple name-value pair object used to categorise a product (e.g. item 1234 may have a category "ballon").
I modelled the product as a root aggregate, which owns and knows how to modify it's category, which is an entity.
However, I ran into a problem where a user needs to be able to search a category. How am I supposed to implement this in DDD? I'm new to DDD but I believe that only root aggregates should be given it's own repository. So that leaves me with 2 options:
Add "SearchCategory" method to the ProductRepository
Implement the search logic as service (i.e. CategoryFinderService)
I personally think option 2 is more logical but it feels weird to have a service that touches database. Somehow I feel that only repository should be allowed to interact with database.
Can someone please tell me what's the best way to implement this?
IMHO, in your Domain Model, Category should not be child of the Product Aggregation. The Product has a Category, but it does not know how to create or edit a Category.
Take this another example. Imagine the ShoppingCart class, it's an aggregate root and contains a list of Items. The ShoppingCart is responsible for adding/editing/removing the Items, in this case you won't need a Repository for the Item class.
Not sure by the way, I'm new to this just like you.
Placing something You don't know where to put into artificial services usually leads to anemic domain model.
I would go with first option. But need for entities without context of root is a sign that You might lack another root.
Don't try to implement everything with your domain model. The domain model is powerful for changing the state of the system, but unnecessary complex for querying. So separate the two. It's called Command Query Responsibility Segregation, or CQRS. And no, it has nothing to do with Event Sourcing, even though they do work nicely together.
I implement scenarios such as this so that I have a domain logic side with the domain objects and repositories (if needed), which do the state changing when something happens, i.e. new order is placed or order is shipped. But when I just need to show something in the UI, for instance the list of the products filtered by the category, it is a simple query and does not involve the domain objects at all. It simply returns Data Transfer Objects (DTO) that do not contain any domain logic at all.