Everything seems to be an Aggregate Root - domain-driven-design

I want to model menus composition in a Restaurant. I've created a very small Bounded Context around just 3 concepts: Menu, Category, Product.
Menus are composed of different Products and every product in each menu is placed under a certain Category (a category is for example, "entrants", "1st course", "2nd course", "dessert"…).
The problem is that everything seems like an Entity to me.
For example, when a Menu is deleted, no Products or Categories are deleted. The same happens when the other 3 concepts.
Regarding the UI, Menus will be consumed like a hierarchy:
Menu1
Category1
Product1
Product2
Category2
Product3
Product4
I'm wondering how to model this. Should I make them 3 Aggregates? Then, how should a compose a Menu in order to be consumed like the hierarchy above?
Thanks.

If you have a menu as an aggregate root with your current arrangement, then what would happen if you wanted to re-use the same product on a different menu? From outside the aggregate root, you wouldn't be able to hold a reference to it.
Instead I think that having Menu and Product (ask the Chef what he would call a food or menu item!) as aggregate roots are fine, as they both exist and have their own identity (you may have different menus over time, a menu may consist of food items that have been used on other menus).
Having the Category as a value object may be more fitting (again, maybe a Chef would call this a Course?) - how many Categories do you have (I believe these courses are probably fixed)? Does a category have its own life-cycle and identity? An enumerable on each product could fit this requirement well.
You also mention about deleting... that sounds like a technical infrastructure term. There are two issues with this:
If you did the above and split in to two aggregate roots (Menus and Products) how would you handle a delete of a Product when a Menu is referencing it? This becomes a transaction across two aggregate roots, which are hard to implement (one of the main ideas of DDD is defining transactional boundaries and enforcement of invariant via aggregates - any external operation on an aggregate root from the outside should leave it in a consistent state).
Think about what the chef or restaurant manager would do - would they delete a menu, or would they instead archive it or make it no longer available for selection?
One resource that will help solidify the above is Effective Aggregate Design by Vaughn Vernon - http://dddcommunity.org/library/vernon_2011/
In terms of code, a psuedo mockup in C# would be below:
public Object HandleGetMenuCommand(
string menuName,
IMenuRepository menuRepository,
ProductRepository productRepostiory)
{
Menu menu = menuRepository.Get(new MenuId(menuName));
List<ProductIds> productsInMenu = menu.Products;
List<Products> products = productRepostiory.GetMany(productsInMenu);
List<string> categories = ... // get a list of unique categories from products
// now assemble products by category...
foreach(var category in categories)
{
var productsInCategory in products.Find(x => x.Category == category);
foreach(var product in productsInCategory)
{
// add this to a list...
}
}
var clientData = new {
name = menu.Name,
// add in the products that were assembled by category above
}
return clientData;
}

I think you are trying to make too much effort putting everything into DDD instead of making focus of the simplicity about this domain by just looking into the "real world. Please let me first go with an plain OO approach and just then let's talk about how to see it with DDD.
So you wanna have Menus so restaurant customers can look at them and choose whatever they want to eat. Let's suppose at the moment there will be just 1 menu for lunch, dinner, every weekday.
The restaurant manager should be able to create this Menu and change it whenever he wants to.
This is our first use case
menu = new Menu("monday lunch", starters, mainEntrees, desserts, drinks);
where each of those parameters are lists of value objects (at first sight).
Just take a look at the real world, a menu is a description of the food you can get in a restaurant, those descriptions are inmutable objects (value objects) so so far we do not need anything else.
At this moment we have only one aggregate root that is Menu. It has global identity and groups a cluster of objects and has invariant. What class would I use to model an entree, dessert? String... an instance of String is enough so far.
What about the menu? We could have many Menus, one for monday, one for tuesday, one for friday night and so on, each having its own global identity so we have for sure the MenuRepository.
What about if the restaurant manager wants to add a new dessert?
menu = menuRepository.get(menuId);
menu.add(aDessert);
is enough.
So far we have one Menu aggregate root and its repository.
I think this is what you asked.
However, I think you missed the price. Each line on the menu would have prices, and two same desserts on different menus may have different prices if its lunch or dinner, so a more realistic approach seems to be:
menu = new Menu("monday lunch", starters, mainEntrees, desserts, drinks);
where starters, mainEntrees, desserts, drinks are a collection of type MenuLine.
Now what happens if the customer tells the waiter to bring him something to eat? a new order needs to be created to keep progress of what the customer asks in order to create an invoice later.
this order needs to know what food the customer asks, I mean what menu item the customer orders. So far we are using value objects to model the desserts, drinks, etc. Right now we should give some form or identifier to those options the customer can choose in order for us to have some unique identifier to use in order contexts such as orders. This is where we determine we need another Aggregate Root (the one you called Product). I would rather call it Food or something like that.
So when the restaurant manager decides to let the restaurant offer a new food the system would be
food = new Food("sushi");
foodRepository.add(food);
and then we the manager wants to add sushi to the menu of monday night
food = foodRepository.getBy(foodId);
menu = menuRepository.findByCriteria(mondayNight)
menu.addAt(food, tenDollars);
and what Menu does is
addAt(food, tenDollars) {
mainEntrees.add(new MenuItem(food.id, food.description, tenDollars)
}
we do not want the Menu to hold a reference to the Food aggregate root because of what vaughn vernon said in its book.
well hope it is helpfull. You do not need the concept of Category at all:
Menu {
List starters;
List entrees;
List desserts;
List drinks;
}
Hope it helps.
Cheers,
Sebastian

Related

Assign products to parent category shopware 5

I'm trying to do something but without luck at the moment. I have a category, let say phones and inside another category as child, let say accessories. This is a easy structure to create, the problem is I can't assign any product to phones (it look like a folder), so I created a phones category inside phones:
phones
--phones
--accessories
This is working too but the url would be website/phones/phones and also this option appears twice in the menu. Is there any way to do this on shopware?
In Shopware 5 you are limited to assign products to the lowest category of a category tree. So there is no option (without extending Shopware 5) to assign a product to parent category.

Event Sourcing - where does Domain Logic fit in?

I've just been watching Greg Youngs talk on Event Sourcing, but i'm confused as to where business logic fits in. A simple example:
1) Shopping Cart Created
2) Item Added
3) Item Added
4) Promotional Code - 20% Off
Is the Promotional Code calculated against the shopping carts items and the result of that stored as an event. I understand "PromotionalCodeAddedEvent" would maybe make sense, but where does the math happen? I'm thinking:
public void AddPromotionalCode(PromotionalCode code)
{
//perform calculation against shopping cart items.
//if valid
ApplyChanges(cmd);
}
Then the result doesn't end up anywhere and the Read Model would have to perform the calculations.
I'm not fully understanding the concept, any help would be great.
Something as seemingly simple as a promotional code can actually be a fairly complex use case. Primarily, this is due to the fact that a promotional code is logic that (usually) is maintained by one or more business users, whereas it also belongs inside of the domain, itself. It is non-traditional, in that sense. There are multiple ways to handle this, and what I will outline would just be my personal approach.
For the sake of argument, assume that you have a simple series of known promotional codes, such as:
X% Off Purchase, with or without a Minimum Purchase
$X Off Purchase, with or without a Minimum Purchase
We can make some assumptions, as well:
A Promotional Code has a Start Date
A Promotional Code has an End Date
The application of a promotional code can be tricky. Consider the two scenarios that we have defined. "$X Off Purchase" is comparatively simple, because it is a fixed amount. "X% Off Purchase", however, is more complex. If we only had the fixed amount, we could apply the discount to the cart as soon as any thresholds are met. With a percentage-based discount, if the user were to add two items, add a promotional code, and then add another item, the promotion would have already been "applied".
Because of this, I would personally only "attach" a promotional code to a cart. Why? The reason is that at the point of checkout, I can likely assume that a cart is going to be used to generate an order. Until that time, the cart's contents are fluid. A user's action against the cart will change the total value of the cart, as well as the total discount, assuming a non-fixed discount amount. It can also render either discount as being invalid, should a user remove one or more items from a cart and the total value of the cart fall below the threshold to apply the discount.
So, I would actually have multiple commands which would would be involved. Essentially any commands that impact the value of the cart could change the discount amount. To that end, I would be looking for the discount amount to be recalculated for the commands which:
Add an item to the cart
Remove an item from the cart
Change the quantity of items in the cart
Add a promotional code to the cart
Change the promotional code attached to the cart
Since these all are operations against a cart, I would be calculating the discount within the promotional code, itself, with the participation of the data contained in the cart. It feels like a promotional code is going to be an aggregate, going down this path. So, I would have the command handlers invoke a domain service that can provide my cart with the information that it requires. That domain service is going to load the promotional code, and I am going to be able to pass in the line items within that cart, so that the promotional code will tell me what the calculated discount would be. Then, I am going to generate the event, which contains the new value of the cart, along with the adjusted value (the discount). Going down this path, the logic for calculating a discount based upon line items within a cart is the responsibility of the promotional code.
You could put this responsibility in the cart, instead. Personally, though, I feel as if encapsulation of domain logic within the promotional code, itself, makes more sense. I had mentioned that it is likely that you will generate an order from a cart. By having the promotional code as an aggregate, and it containing the logic to apply the discount based upon the line items, we have a single truth, in how we calculate a discount for line items - whether that is in terms of a cart or in terms of an order.
You can, for example, raise a second event such as PromotionalCodeApplied which contains the computation results.
The Read Model then just have to use the pre-computed result.
I understand "PromotionalCodeAddedEvent" would maybe make sense, but where does the math happen?
It should happen in commands that perform modifications to the shopping cart. Every such command will call some method like RecalculateTotals() where all business logic will be hosted.
Consider the following pseudocode:
public void AddPromotionalCode(PromotionalCode code)
{
var #event = new PromotionalCodeAdded(code);
var amount = RecalculateTotalAmount(extraEvent: #event);
#event.TotalAmount = amount;
_eventStore.Publish(#event);
}
decimal RecalculateTotalAmount(IEvent extraEvent)
{
var relatedEventTypes = new[] { typeof(PromotionalCodeAdded), typeof(ShoppingCartCreated), typeof(ItemAdded) };
var events = _eventStore.ReadEventsOfTypes(relatedEventTypes);
var events = events.Concat(new[] { extraEvent });
//calculation logic goes here based on all related events
}
This is where I like to return events from command methods. As Alexander Langer mentioned, you'd apply the "math" and return the relevant event(s):
public PromotionalCodeApplied AddPromotionalCode(PromotionalCode code)
{
//perform calculation against shopping cart items.
var promotionalCodeApplied = new PromotionalCodeApplied(code.VoucherNumber, discountAmount, DateTime.Now);
On(promotionalCodeApplied);
return promotionalCodeApplied;
}
public void On(PromotionalCodeApplied promotionalCodeApplied)
{
_voucherNumber = promotionalCodeApplied.VoucherNumber;
_discountAmount = promotionalCodeApplied.DiscountAmount;
_discountDate = promotionalCodeApplied.DateAppllied;
}
Now your read model has access to the relevant values.

How can a child of an aggregate root use values from another aggregate root

For example, consider a store having multiple menus. Menus list items and one item can be listed in multiple menus.
Imagining a Menu aggregate root and Item aggregate root. A Menu would have a collection of MenuItem's who reference an Item AR along with ordering information within the particular menu.
My question is, how would you access the Item's name, price, description from the MenuItem. Say, for instance, the Menu AR handles a command to re-order itself by price (I know that sounds UI related, but I'm strictly talking domain model here, idk maybe it's a business rule that a menu must be sorted in a particular way? )
Would you obtain a Value Object for the Item AR inside the MenuItem? If so, would the Menu AR hold a reference to a domain service to lookup the value object for the Item, or would the MenuItem use the domain service.
I guess, the Menu AR should be consistent at all times and that could mean that when an Item is added to a Menu, the MenuItem holds a reference to a value object for the Item.
Sounds like that would break the 'reference entities by identity' rule, so the MenuItem would hold a reference to ItemId. Considering the use of event sourcing, whenever you'd want to apply a command to the Menu AR, it would replay all of it's events bringing it into consistency and then you issue a command to re-order the menu's items.
The MenuItem would only have a ItemId and not the details of that item, would this be the time to load those items? The Menu could loop over it's MenuItems then use a service to lookup a Item value object by ItemId for each MenuItem and then perform the sorting.
Thanks for any input, greatly appreciated.
Like you said, this should probably be done in the query side. I'm not sure that I see how keeping the ordering consistent in the domain would be of any use? Perhaps I would if menus had different ordering strategies, but even then. Anyway...
If the data used by an AR is not within it's boundary then it may only be made eventually consistent, unless you modify more than a single AR per transaction which is usually a bad practice.
You may do something like that:
menu = menuRepository.findById(menuId);
menu.reorder(itemPricingService);
Some also prefer to resolve dependencies in the application service/command handler:
menu = menuRepository.findById(menuId);
itemIdList = menu.items().map(extractItemId);
itemPriceList = itemPricingService.pricesOf(itemIdList);
menu.reorder(itemPriceList);
However, you will also need to listen to an event such as ItemPriceChanged in order to keep the menu ordering consistent with price changes.
There's also another strategy where you could copy over pricing information to the MenuItem. The price would be kept eventually consistent relying on events and a reorder would occur from the item of which the price changed.
You may use a similar reordering strategy as implemented here. Have a look at the reorderFrom implementation of Product and ProductBacklogItem.

How to make global views in SharePoint

I have a SharePoint site, where I need to locate different kinds of surveys, to divide them into different quick launches: Like, if I have Gardening, Painting and ext. quick launches I want surveys about gardening to be in Gardening launch, about painting in Painting launch and so on.
I decided to create a list ("Surveys List"), where will be all this surveys that user creates. List has a column - genre (column type: choice).
What I want is to create global views to do next: All surveys with gardening genre put into Gardening view , paintings in Painting and so on. I did views, which was visible in just "Surveys List" view. Of course, making with global views work is not done, mission is not accomplished.
As I'm really new in SharePoint probably there is So many better ways to do all that stuff, which I don't know. If anybody knows how to make global views or solve this problem, please help.
Thanks
There is no such thing as a "global view" in SharePoint - a view is always tied to one list.
You can create an identical view on another list but its just a copy.

How do I modify the Magento Search to check child skus?

Currently, the site search will search all of the skus of the items marked as being visible in search. This is all well and good.
The problem arises when the customer knows a sku of the individual child item. So, let's say a product comes in both a 20 foot and 25 foot variation. We would put those into a configurable product and have a single product page where a customer could then choose which of those two lengths.
What happens is, a customer invariably knows that the sku of the 20 ft variation is RDB-20, while the other is RDB-25. A search for RDB-25 then, comes back with no results since the simple product is not visible in search - it doesn't realize there is a match.
How do I get the search to search an item with visibility "Not Visible Individually", when it's parent is visible in search?
The desired effect is that, if a child SKU is searched for, the parent should show up in the results.
There really is no good way of doing it without extending the default search, but at that point you might as well look for other options.
Here's a workaround that might be doable depending on how you manage your products and it worked for me until I moved on from the default search.
Rather than altering the search, try adding an attribute to all products and make it hidden concatenating all the skus into this field. The search should find the text attribute and show the configurable.
Its a bit of a workaround but works for me.
This is untested, but I did a bit of perusing in our attributes and I think I found something that might help.
Currently since our child products don't show up in our search, we have the parent populate with the children product's attributes.
However, things like brand, taxable amount, description, populate for every child product while our SKU does not.
The only difference I can see between the two attributes is under manage attributes -> click on attribute -> and then under properties go to frontend properties and select
Use In Search Results Layered Navigation: YES
Used in Product Listing: YES
Use In Layered Navigation: Filterable (with results)
I'm not sure which of these do what, but in the population of the fulltext search data table, somewhere it is being told to populate for the children and I believe that the admin panel is where.
I hope this helps!

Resources