views:

322

answers:

2

Two part questions

I have a product aggregate that has;

Prices PackagingOptions ProductDescriptions ProductImages etc

I have modeled one product repository and did not create individual repositories for any of the child classes. All db operations are handled through product repository.

Am I understanding the DDD concept correctly so far? Sometimes the question comes to my mind that having a repository for lets say packaging options could make my life easier by directly fetching a the packaging option from the DB by using its ID instead of asking the product repository to find it in its PackagingOptions collection and give it to me..

Second part is managing the edit create operations using ASP.MVC frame work

I am currently trying to manage all add edit remove of these child collections of product through product controller(sound right?).

One challenge I am now facing is;

If I edit a specific packaging option of product through

mydomain/product/editpackagingoption/10

I have access to the id of the packaging option

But I don't have the ID of the product it self and this forces me to write a query to first find the product that has this specific packaging option then edit that product and the revelant packaging option. I can do this as all packaging option have their unique ID but this would fail if I have collections that don't have unique ID.

That feels very wrong..

The next option I thought of is sending both the product and packaging option IDs on the url like;

mydomain/product/editpackagingoption/3/10

But I am not sure if that is a good design either.

So I am at a point that I am a bit confused. might be having fundamental misunderstandings around all of this...

I would appreciate if you bear with the long question and help me put this together. thanks!

+2  A: 

In my mind, this is one of those muddy things that pops into DDD.

In code, I treat an aggregate root as a container for any "relationships" it has and any Entity Objects that cannot exist without the Aggregate root.

For instance, let's take the Customer->Order->LineItem->Product example that's been bludgeoned to death by now. The aggregate root as I've displayed it is customer in this scenario. That stated, you don't always want to get to the order through the customer. You might want to find orders on a specific date.

Turning it on it's side, you also wouldn't have a Customer that doesn't have an order. The two are in a somewhat symbiotic relationship so one isn't the aggregate root of the other.

The point is that you don't want to have to load a customer through an order, but you don't necessarily want to load an order through the customer either.

Starting at Order, however, it's unlikely that you'd want to just retrieve a LineItem and you're certainly not going to be creating them w/o an order. To that end, the Order serves as the gateway to LineItems. LineItems wouldn't need their own controller or repository. They only exist within the Order itself and, as such, are part of the Order (in this case, Order becomes the aggregate root) and are managed by the Order Entity.

But, a LineItem would likely have a relationship to a Product within the system. Products would have their own controllers, repositories, etc because they can exist outside of the Aggregate root.

In summary to my rambling, I tend to look at it this way: if an Entity can exist by itself, it should have a controller. Entities that cannot exist on their own (LineItems in this case) should only be managed solely by their container (aggregate root).

Will some DDD purist please correct me if/where I'm wrong?

As to the second part of your question, I would need some more details about how you envision these other Entities working. With what you've put here, I'd imagine that PackagingOptions are related to a product and would be part of a Product aggregate root. Now, implying that you're editing them begs the question of is this a lookup table in the system or are they one-off values and, as such, should be treated as Value Objects?

andymeadows
Thanks for your answer. It sounds like we were kind of on the same page till I got my self to a more radical approach to aggregate roots that brought up all these questions.. Regarding your question; packagingoption I think should be value objects, I will look into it again. But my question remains regarding how to do edit scenarios for the entities of an aggregate root where I pass the controller the id of the child entity and it is upto the aggregate controller to handle all the rest - i kind of resonate towards sending both aggregate id and child id for these cases but still feels messy
kaivalya
I would argue that if a child entity has an id and that entity needs to be edited, it warrants its own controller. As for getting the parent relationship, if it's 1:1 then store the parent id with the child and just grab it but saving the parent to modify a child that has its own id is a little smelly to me. If you are editing the entity itself, then you're not editing the aggregate and you have something that should be able to stand on its own. It seems to me like you want to edit the Product by loading an order and that won't work. Also, Value Objects have no identity -- well, usually.
andymeadows
See http://devlicio.us/blogs/casey/archive/2009/02/13/ddd-entities-and-value-objects.aspx as a starting point for a discussion on Entities and Value Objects.
andymeadows
And one more comment... if you're editing a child of the aggregate root without loading the aggregate, then it's incorrect in the first place. You should already have the aggregate root loaded. You wouldn't directly load a LineItem -- and you shouldn't. You'd load the Order and allow them to edit a LineItem within the context of that order. Then you'd simply "save" the order and your child Entities would be saved. You could add some IsDirty checks, but the parent is always the gateway and you should (almost) never expose the ID of a child assuming it has one.
andymeadows
You are right - but im working on stateless http and the sub-module is responsible for editing a child node of the entity, this is the reason i was considering passing both the id of the aggregate root and the id of the entity that I want to edit, hence I can load the aggregate root then find the child that has that id and edit it then update the whole aggregate root..
kaivalya
Define "sub-module". And -- mind you I don't like this solution -- I'd just have a repository method that says "LoadXHavingY" where Y is the child entity and it takes the child entity or entity id as a parameter but returns the aggregate root. You're going to get into smelly code though because you're going to load the child entity by ID, edit it, but saving involves loading the aggregate root, modifying the appropriate child, and then saving it out. Goes back to Value Objects. Hope this has helped.
andymeadows
Thanks for keeping up Andy. See my initial question that's where I mention loading the aggregate from the child as the current solution that I implemented for my problem but as you say its very smelly.. Actually this discussion is driving me towards a different way of handling my data input. If I am dealing with aggregates per controller I am now resonating towards taking all input using jquery on the view and doing a post that contains the complete agregate info which include the childs instead of trying to do individual http posts for child sections of the aggregate..
kaivalya
And that would seem to be much cleaner, both in implementation and presentation. Let me know how it works out. Each implementation is always different and writing code is still more art than science.
andymeadows
+1  A: 

Kaivalya,

Regarding your last comment (stateless http):

It depends on the context. Before getting into the details, I should tell you a basic principle about aggregates:

Aggregates define a group of related objects that should be treated as a single unit for the purpose of data change.

This is extremely important. The purpose of having Aggregates is to enforce invariants. For example, you may have a policy like "An Order cannot exceed $500". Then, to enforce this policy, you put Order and OrderItem together in the Order Aggregate. This way, any time you add a new OrderItem, it should be added via Order object. There, you can check the total price and make sure it does not exceed $500. If you don't have such invariants in your domain, then there is no point loading all these objects together.

Now, getting back to your comment:

If you do have invariants that should be enforced, then it is okay to load the entire aggregate even though it may have some overhead. Yes, HTTP is stateless and you load your whole aggregate just for modifying one of its child objects and then throw it out. That is okay. What is important the most here is that you are enforcing your invariants. This is what DDD is for.

The purpose of DDD is to capture all business logics in your domain. You could definitely achieve a better performance if you didn't have to load the entire aggregate, but how would you enforce your invariants? You'd most likely have to do it in your stored procedure. Yes, it works, and it is fast, but dealing with business logics in stored procedures during maintenance is a nightmare. That is why DDD has evolved. So you can model your business requirements using object-oriented languages/tools, so they are easier to understand and modify.

Just remember, DDD is a great approach but not for all types of projects. If you are dealing with a project in which there are lots of business logics and the chances of them changing due to the nature of a business is high, then you should use DDD. However, if your project is more of a "read something/writing something" without much business logic involved, using DDD is a headache. You could simply use LINQ to SQL (or SqlDataAdapters) and send your objects to your Views. You don't even have to worry about finding Entities, Value Objects, Aggregates, Repositories, etc.

Hope this helps,

Mosh

Mosh