As an exercise I am trying to create a simple blog app in .NET, employing DDD. So far I have User, Topic and Comment classes. But the problem is how to link Comment with User and Topic? If I say that User and Topic are aggregate roots, where does Comment belong?
Aggregates may have associations to other aggregate roots.
e.g. a comment may have an association to both topic and user.
Thats how I would model it anyway, aggregate roots are boundaries of consistency.
A Topic does not need to be consistent in any way with its comments, thus comments does not need to be part of that aggregate.
A user does not need to be consistent with all of his or her comments so users does not need to know about comments either.
I would fetch the comments for a specific topic by the comment repository.
e.g.
var comments = commentRepo.FindCommentsForTopic(someTopic);
//or by topic id for pragmatic reasons.
Related
Sorry for poor English.
When learning about DDD , i have a question about aggregate.
In Board domain, we have two entity, One is Post, another is Comment.
I think Comment can't exist without Post. So I think Comment should be in Post Aggregate and Board domain has one aggregate which root is Post.
But from a different perspective, entities in the same aggregate have same life cycle,
so Comment life cycle is different from Post's life cycle,
and modifying Post doesn't affect Comment and vice versa.
So Board domain has two aggregate,
one is aggregate which root is Comment and another is aggregate which root is Post
This two think makes me feeling mess.
I've been there before, and I learned it the hard way. At first, it seems natural to have the comments part of the post aggregate but here are the limitations you might face with this design.
It can happen that you need to delete the post and keep the comments. Same as you see on some social media platforms.
A post can have a lot of comments to the point that it becomes expensive to load them all in memory each time you fetch a post.
Users can interact with comments directly (reactions, comment on a comment, share, mention other users ...) hence it is easier if the comment can be uniquely identified across the system.
You might need to list all comments of a user. It becomes harder when the comment is part of the post aggregate.
It is safer to have PostComment as a separate aggregate and keep a reference of the post. And as a general rule for designing aggregates, you should keep them as small as possible.
I recommend to read this brilliant article. That changes your perspective to aggregate design rules.
Effective Aggregate Design Part I: Modeling a Single Aggregate
I have the following entities (example):
Book
Author
The Book entity is also an aggregate since it has related one or many Authors. Now I have a problem in how to fetch this aggregate from the repo. I have the following cases - and I also do need to take care of performance:
List all the Books. No need to fetch Authors.
List all the Bookss with Authors names. Obviously, we need to fetch the aggregate of Books and related Authors.
List all the Books with authors count. Similar to (2), except I do not want to fetch the Authors from the repo, just the count.
So how my repository should look like? Specific questions:
Should we have method like findBooks and findBooksWithAuthors and findBooksWithAuthorsCount? But this would lead to crazy amount of methods, since our entities have many relationships between each other.
Should we just have findBooks and then loadAuthors in AuthorsRepo, i.e. not doing the join, until we hit some performance issue, and then to refactor.
Should I create some aggregate-value-objects, like: BookAndAuthors that describes relationships?
Please note that this example is trivial - and you have to know that our models are more rich and have more relationships.
Do you need to fetch this kind of information to display on the UI ?,
I would encourage you to separate your read and write concerns, and keep your repository interface simple (similar to that of a collections interface).
Have a look at CQRS, it works very well with DDD and will help simplify your design to a great deal.
Once you get into CQRS, just keep in mind that CQRS does not necessarily involve Event Sourcing.
In your case I would recommend the simplest approach show in this article, basically have a read service (can call it Finder), which fires SQL and gets you a DTO/Map of whatever you need for the UI.
Everything I have read thus far on DDD implies only entities which encapsulate other entities are root aggregates.
What about in situations like:
WorkOrder
- idManufacturer
- WONumber
- Description
Manufacturer
- idSelf
- Name
WorkOrder references Manufacturer but would not be a child of WorkOrder as other entities might reference WorkOrder, in this case I would consider both Root entities, but the Manufacturer is not an aggregate...
Is this correct?
I once had a lightbulb moment with DDD when someone told me that entities with no children can be though of as aggregate roots.
Particularly when someone says "persist only your aggregate roots".
In your example, your aggregate roots are WorkOrder and Manufacturer. You'd have a repository for WorkOrder and one for Manufacturer.
In fact, you will mostly have aggregates with value objects only. ARs with child entites are rare. Read red book (Implementing DDD Vaughn Vernon), there is described rule of small aggregates.
The job of an aggregate root is to encapsulate and enforce invariants. It may consist of other objects but they are all interacted with through the AR. The important thing to remember about an aggregate, is that is should be independent of your chosen persistence mechanism. The majority of your aggregates should have no dependencies at all!
I may be mistaken but it looks like the idManufacturer is a foreign key. This would suggest (not always the case) it is not encapsulated. The thing that took me a while to get my head around was that the fields within an aggregate are private. This raises the question of how you save it's state and how you get data to put on the UI. There are lots of ways to that. My preferred approach is to use Event Sourcing and CQRS. I can then build out UI's from the events that my aggregates produce. I can also persist those events and use them to rebuild my aggregate.
I've gone into a lot more depth on my blog, you may want to take a look at How to Build an Aggregate Root! . You may also find helpful a post on building a master details screen when using CQRS and Event sourcing, that can be found here!
I hope that helps.
Domain Driven Design can be really confusing at times and since I am rather new to this technique I would like to have some answers regarding those scenarios that are currently bugging me.
Here a simple diagram to represent my question using DDD principles. My question is about aggregate roots, domain validation and "ways to do" or best practices.
In this scenario, how would you implement a way to count the number of comments written by a user? Would it be a method in "Review"? Or would it be best to be a method in a repository (ReviewRepository)?
How do I make other entities access comments if they need to? Having this scenario, does that mean that Comment isn't part anymore of the "Review" aggregates?
What if comment have a composition relationship with some other entity? How would you manage the access to that entity? Is comment responsible of this entity or the root?
Any other suggestions or facts regarding this model? Any best practices I should fellow when designing a model?
Thanks.
NOTE: The answer must fellow DDD principles
There a little error in the Review entity. "Compte" in the Add method is "Account" and should be A instead of C.
In this scenario, how would you implement a way to count the number of comments written by an user ?
Responsibility belongs with review. It's an aggregate of comments. Count is a first-class feature of any aggregate.
How do i make others entities access comments if they need to ?
Comments are accessible via a Review. A Review is an aggregate of comments.
What if comment have a composition relationship with some other entity ?
"What if" questions are hard to answer without a concrete and specific example. After all, the design is driven by the problem domain, not random thoughts.
If some "other" entity also appears to be a composition of Comments, you have to go back to the domain experts and try to determine where the real responsibility lies.
One pair of question is "if the review is removed, what happens to the comments?" and "If the mysterious 'other' is removed, what happens to the comments?" This can help find the responsibilities.
I'm still wrapping my head around DDD, and one of the stumbling blocks I've encountered is in how to handle associations between separate aggregates. Say I've got one aggregate encapsulating Customers and another encapsulating Shipments.
For business reasons Shipments are their own aggregates, and yet they need to be explicitly tied to Customers. Should my Customer domain entity have a list of Shipments? If so, how do I populate this list at the repository level - given I'll have a CustomerRepository and a ShipmentRepository (one repo per aggregate)?
I'm saying 'association' rather than 'relationship' because I want to stress that this is a domain decision, not an infrastructure one - I'm designing the system from the model first.
Edit: I know I don't need to model tables directly to objects - that's the reason I'm designing the model first. At this point I don't care about the database at all - just the associations between these two aggregates.
There's no reason your ShipmentRepository can't aggregate customer data into your shipment models. Repositories do not have to have a 1-to-1 mapping with tables.
I have several repositories which combine multiple tables into a single domain model.
I think there's two levels of answering this question. At one level, the question is how do I populate the relationship between customer and shipment. I really like the "fill" semantics where your shipment repository can have a fillOrders( List customers, ....).
The other level is "how do I handle the denormalized domain models that are a part of DDD". And "Customer" is probably the best example of them all, because it simply shows up in such a lot of different contexts; almost all your processes have customer in them and the context of the customer is usually extremely varied. At max half the time you are interested in the "orders". If my understanding of the domain was perfect when starting, I'd never make a customer domain concept. But it's not, so I always end up making the Customer object. I still remember the project where I after 3 years felt that I was able to make the proper "Customer" domain model. I would be looking for the alternate and more detailed concepts that also represent the customer; PotentialCustomer, OrderingCustomer, CustomerWithOrders and probably a few others; sorry the names aren't better. I'll need some more time for that ;)
Shipment has relation many-to-one relationship with Customer.
If your are looking for the shipments of a client, add a query to your shipment repository that takes a client parameter.
In general, I don't create one-to-mane associations between entities when the many side is not limited.