Can someone check my class diagram because I am not too good at drawing this type of uml diagram
A User can be a PersonalUser or a BusinessUser
An Administrator is a special type of PersonalUser
A PersonalUser or BusinessUser can create many Auction
But an Auction can be created by only one PersonalUser or only one BusinessUser
There an Auction cannot exist without an PersonalUser or a BusinessUser
An Auction can contain only one Item
An Item can be in only one Auction
An Item cannot exist without an Auction
An Auction cannot exist without an Item
An Item has one Category
Category can has many item
An Item cannot exist without a category
A Category can has a Parent Category but this is not mandatory
A Category can has many Attributes
But an Attribute is for only one Category
An Attribute cannot exist a Category
An Attribute can has many AttributeOption
But an AttributeOption is linked to only one Attribute
An AttributeOption cannot exist without an Attribute
An Auction can has many bids
A bid is only for one auction
A Bid cannot exist without an Auction and a Personal User or a BusinessUser
An Item can has many picture
A picture is only for once item and a picture cannot exist without an Item
A User can create many ForumTopics but a ForumTopic can be created only by one User
A ForumTopics can contain one or more ForumMessage
A ForumTopic cannot exist without a User and a ForumMessage cannot exist without a ForumTopic
A BusinessUser can has many BusinessContactNumber but a BusinessContactNumber is only for one BusinessUser
A BusinessContactNumber cannot exist without a Business
At first glance, you used a lot of aggregations. This is quite uncommon. I have never seen a good example of when an aggregation is justified. It's usually either a plain association (no whole-part relationship) or a composition (the part is deleted when the whole is deleted).
Cannot exists without does not imply aggregation. A proper multiplicity is sufficient. Can create does not imply aggregation. Creation is usually modeled with an appropriately stereotyped use-relation (i.e. dashed arrow), unless an association between the creator and the creation exists (in which case creation need not be mentioned explicitly).
4 But an Auction can be created by only one PersonalUser or only one BusinessUser.
Then the multiplicity of the Auction-PersonalUser association cannot be 1 at the PersonalUser end (because the Auction might have been created by a BusinessUser) and the multiplicity of the Auction-BusinessUser association cannot be 1 at the BusinessUser end (for much the same reason). Use 0..1 as multiplicity, but beware of what I will write about 3.
3 A PersonalUser or BusinessUser can create many Auction
This is equivalent to a User can create many Auction.
6 An Auction can contain only one Item
7 An Item can be in only one Auction
8 An Item cannot exist without an Auction
9 An Auction cannot exist without an Item
Then there is a single association between Item and Auction with multiplicity of 1 at both ends. Don't make aggregations out of it and don't use two associations for it.
13 A Category can has a Parent Category but this is not mandatory
That would be made clear if you label the association ends.
25 A User can create many ForumTopics but a ForumTopic can be created only by one User
This is only vaguely related to Auctions and might as well exists independent of them. Put the Forum stuff into a separate package. Then maybe the auction stuff and the user stuff also deserve a separate packages.
BTW: You did not mention the Bidding Service. It seems solely to model the concept of theses objects do not exist in thin air, they are actually used by some software. In that case, leave it out.
I largely agree with previous respondent, so I will present only differences and additional opinions.
To be a bit more precise, "Can create..." should be depicted using dependency relationship (not uses).
It is not entirely equivalent if some distinction should exist. You might use User class with an enumeration or UserType class if you want to avoid enumerations for some reason.
6.-9. So no Auction or Item object can exist. Either loosen the relationship in one way and use composition or merge those two to one class or create an association class.
Maybe one category can contain many subcategories? If true, edit the corresponding multiplicity.
Same as 4., view the other answer.
Also rethink the amount of classes in your design. Classes are not just data holders, they should have behaviour. What will be the behaviour of AttributeOption or Attribute or BusinessContact etc? Getters and setters do not count for a behaviour... I guess you planned to have all of this behaviour in BidingService, so I advise you to remove it and split those methods according to what class of objects should be responsible for behaviour achieved through the respective method.
Related
In my domain model I have the project entity (which is also aggregate root) which has products entity as child. One of the invariants of my domain model is that I can't have two products with the same code children of the same project (but is ok if the project is different).
My products are composed by parts which also has a similar rule (every part must have unique code within the same product) so parts are child of products because I need to ensure that rule. Children of product are also the activities that I need to do to create it because I'm describing a production tracking system.
Now, activities can have subactivities which can be assigned to factory area and so on.
Substantially what I have is that all entities starts from project just because I need to ensure one invariant(=business rule) but is not the best solution because every time I need to retrieve an entity I need to fill all the project (which can have 2000+ products).
What can I do to split that preserving my invariant but also freeing me to load a specific activity (or product) without retrieving all products of my project every time I need a child entity?
Should I need to split the Entities in several AggregateRoots, maintaining in the project a list of ProjectProductValueObject(string code) and use Domain Events in Aggregate's constructor to fire something like ProductCreatedEvent which try to create and add a new ProjectProductValueObject in my project using the AddProduct(ProjectProductValueObject product) method which contain my business rule and throws an exception if that's not satisfied? Is that ok and compliant to DDD principles?
Do I have other alternatives?
I have the feeling that you're overcomplicating the model.
From your description I've understood that:
Projects are root entities that can contain a list of
AssignedProduct, that is another root entity that contains a binding between the project (its id, see as a value object) and the product (I see it also as a value object)
So on with object and assigned object
In this way you've several Products that could be assigned to several Projects, but only the ones stored in AssignedProduct are valid. To avoid multiple assignments is just a matter of checking if the same couple of objects are already bound together.
If this doesn't match your model, ignore it.
First, don't think i'm trying to get the job done by someone else, but i'm trying to design a class diagram for a domain model and something I do is probably wrong because I'm stuck, so I just want to get hints about what i'm not doing correctly to continue...
For example, the user needs to search products by categories from a product list. Each category may have subcategories which may have subcategories, etc.
The first diagram I made was this (simplified):
The user also needs to get a tree list of categories which have at least one product.
For example, if this is all the categories tree:
Music instruments
Wind
String
Guitars
Violins
Percussion
Books
Comics
Fiction
Romance
I can't return a tree of Category which have at least one product because I would also get all subCategories, but not each sub category has a product associated to it.
I also can't remove items from the Category.subCategories collection to keep only items which have associated products because it would alter the Category entity, which may be shared elsewhere, this is not what I want.
I thought of doing a copy, but than I would get 2 different instances of the same entity in the same context, isn't it a bad thing ?
So I redesigned to this:
Now I don't get a collection of child categories I don't want with each Category, I only know about its parent category, which is ok.
However, this creates a tree of categories which is navigable only from the bottom to the top, it makes no sense for the client of ProductList who will always need a top -> bottom navigation of categories.
As a solution I think of the diagram below, but i'm not sure it is very good because it kinda dupplicates things, also the CategoryTreeItem does not seems very meaningful in the domain language.
What am I doing wrong ?
This is rather an algorithmic question than a model question. Your first approach is totally ok, unless you were silent about constraints. So you can assign a category or a sub-category to any product. If you assign a sub-category, this means as per this model, the product will also have the parent category. To make it clear I would attach a constraint that tells that a product needs to be assigned to the most finest know category grain. E.g. the guitar products would be assigned to the Guitar category. As more strange instrument like the Stick would get the Strings category (which not would mean its a guitar and a violin but just in the higher category.
Now when you will implement Category you might think of a method to return a collection of assignedInstruments() which for Guitar would return Fender, Alhambra, etc. You might augment this assignedInstruments(levelUp:BOOL) to get also those instruments of the category above.
Generally you must be clear about what the category assignment basically means. If you change the assignment the product will end up in another list.
It depends on the purpose of the diagram. Do you apply a certain software development method that defines the purpose of this diagram in a certain context and the intended readers audience?
Because you talk about a 'domain model', I guess your goal is to provide a kind of conceptual model, i.e. a model of the concepts needed to communicate the application's functionality to end users, testers etc. In that case, the first and the second diagram are both valid, but without the operations (FilterByCategory and GetCategories), because these are not relevant for that audience. The fact that the GUI only displays a subset of the full category tree is usually not expressed in a UML diagram, but in plain text.
On the other hand, if your intention is to provide a technical design for developers, then the third diagram is valid. The developers probably need a class to persist categories in the database ('Category') and a separate class to supply categories to the GUI ('CategoryTreeItem'). You are right that this distinction is not meaningful in the domain language, but in a technical design, it is common to have such additional classes. Please check with the developers if your model is compatible with the programming language and libraries/frameworks they use.
One final remark:
In the first diagram, you specified multiplicity=1 on the parent side. This would mean that every Category has a parent, which is obviously not true. The second diagram has the correct multiplicity: 0..1. The third diagram has an incorrect multiplicity=1 on the composition of CategoryTreeItem.
From my perspective your design is overly complex.
Crafting a domain model around querying needs is usually the wrong approach. Domain models are most useful to express domain behaviors. In other words, to process commands and protect invariants within the correct boundaries.
If your Product Aggregate Root (AR) references a Category AR by id and this relationship is stored in a relationnal DB then you can easily fulfill any of the mentionned querying use cases with a simple DB query. You'd start by gathering a flat representation of the tree which could then be used to construct an in-memory tree.
These queries could be exposed through a ProductQueryService that is part of the application layer, not the domain as those aren't used to enforce domain rules or invariants: I assumed they are used to fullfil reporting or UI display needs. It is there you could have a concept such as ProductCategoryTreeItemDTO for the in-memory representation.
You are also using the wrong terms according to DDD tactical patterns in your diagrams which is very misleading. An AR is an Entity, but an Entity is not necessarily an AR. The Entity term is mostly used to refer to a concept that is uniquely identified within the boundary of it's AR only, but not globally.
I am learning DDD concepts and to strengthen my understanding I am working on some real world examples.
I know that an aggregate should have only one entry point through the root entity and an aggregate should have only one repository (please correct me if I understood it totally wrong)
Now assume that there are consumables with specific types and these consumables are sent from a distribution center. Sending specific types of consumables depends on their quantity, I mean if one of the consumers has a critic quantity 10 for type A and B and those item quantities fall under 10 then the distribution center sends type A and B consumables. Here both the sender and consumer wants to track where the sent package is or if it is delivered or sent at all.
So here, as entities, we have:
Consumable
ConsumableType
ConsumableActivity
Package
PackageItem
Consumer
I am confused about the first three entities: which one should be the aggregate root? In a fast look it seems that the consumable is a strong candidate but on the other hand we do not care about every consumable, we are only interested in their quantity. We don't record 10 different type A consumables but only have a type A record with quantity which changes according to activities. At this point Consumable entity seems redundant, by just looking at activities we can derive the quantity. For example starting from scratch:
Center Create "Type A" 10
Center Create "Type B" 20
Center Send "Type A" 5 ConsumerId=25
Center Send "Type B" 15 ConsumerId=25
ConsumerId=25 Receive "Type A" 5
ConsumerId=25 Receive "Type B" 15
ConsumerId=25 Consume "Type A" 3
ConsumerId=25 Consume "Type B" 1
ConsumerId=25 Consume "Type A" 2
Here we can derive that there are 5 Type A and B consumables at the center and 0 Type A, 14 Type B consumables at consumer with id 25 for now.
Of course this is not an effective approach while after there are much more activities it will take some time to derive consumable quantities, so there should be a static quantity field for every consumable type both for consumers and the distribution center in which we can read the current quantity at once.
I hope you get why I am confused, the consumable entity looks like a root entity but actually it doesn't really fit in to be a root entity if not an entity also.
Can anyone suggest me some improvements about this design or and further reading recommendations which are not limited to customer-product-order-orderline nightmare?
Edit : What is the relation with Consumable and ConsumableType ? What if I want to conduct CRUD operations on ConsumableType (to make the user add new types, change or delete them) but the root entity is Consumable. In order to DDD to preserve data integrity we should't load any repository other than the root entity repository.
Edit 2: Think about a Product entity and its Category entity. The Product seems to be the root entity but we know that products cannot exist without a category. So is the Category entity the root? If so, according to DDD rules, we can access products only by traversing. But in our context the Product is our focus. Then it is supposed that we have two aggregates: Product Aggregate and Category Aggregate. But this time we violate the data integrity because a category may be deleted without deleting products having this category. So I am confused a lot and couldn't find a proper solution.
I am confused about the first three entities: which one should be the
aggregate root?
I am going to say that, most likely, your aggregate is Package even though there is the possibility that this example should be split into two or more separate bounded contexts. (creation and order fulfillment are natural boundaries)
What is the relation with Consumable and ConsumableType ?
It depends on your bounded context. Without knowing any more about ConsumableType other than it is designated by "A" or "B", I would have to say that it is more than likely a value object of Consumable.
What if I want to conduct CRUD operations on ConsumableType (to make
the user add new types, change or delete them) but the root entity is
Consumable
This is most likely a different bounded context altogether (context of some manager or something that doesn't fall within the general workflow we're modeling) for which more investigation about this context is suggested.
[Different Example]
So is the Category entity the root?
The aggregate root is what the user in the context interacts with. Assuming ALOT because you don't fully explain the context in this example, most likely the Product is the aggregate root because that is what the user cares most about. Same as the above example, Product would have a repository that would load it's assigned category to it. Loading the list of categories or hierarchy is best served by a domain service in this case because it doesn't belong to any particular entity instance.
[Another Example]
in your first case, how can, for example a system administrator, list
all available font colors or add a new one?
Again, the context of a system administrator is not the same context as the user who chooses the font color. Remember, each context is a single workflow. In complex workflows, there can be multiple users in the same context, but for the simple workflows like the CRUD operations an administrator might perform, generally there is only one role for this type of workflow. Under the system administrator, AvailableFontColor might be an entity with a Color value property within the Content Decoration Options Administration bounded context.
Can anyone suggest me some improvements about this design or and
further reading recommendations which are not limited to
customer-product-order-orderline nightmare?
I would suggest that you learn more about bounded contexts and why they are one of your most useful (and most hampering at times) tools in modeling a business domain. Also, don't expect to have this perfected to a science within a week.
I have been modeling software using various techniques for over 8 years now and there are still times where I have trouble deciding if I modeled something correctly or not. I think one of the greatest benefits of DDD is that it encourages you to embrace the fact that you probably won't model correctly from the beginning so you should make it easy to change the model and refactor often as you learn more about your domain rather than just going with what you have and ending up with 15 different convoluted cludges around your original model because you didn't fully understand the domain from the beginning.
Marked my aggregate roots with 1;2;3. Looks quite nice - almost like grapes.
Thing I dislike is an entity that's marked with red arrow.
Let's imagine that:
AR #1 is company
AR #2 is office
AR #3 is employee
Entity marked with red arrow is named Country
Company sets the rules from which countries it hires employees (on hiring, company.Countries.Contains(employee.Country) must be true)
I somehow see this quite unimportant part of domain (maybe it does not sound like that in this example one), and I would like to avoid promoting Country to aggregate root.
Glossary about aggregate roots says:
Transient references to the internal members can be passed out for use within a single operation only.
So - does introducing something like 'EmployeeCountry', removing reference to company Country and checking if Employee country matches any company country on hiring operation sounds reasonable?
Any other ideas?
How can I get my grapes look like they should?
In this context Country is just a value object, not an entity - much less an aggregate root - so there's no reason to change anything about your design (without more information).
Additionally, note that the warning you cite pertains to internal members of aggregate roots, not aggregates themselves. There's nothing wrong with maintaining references to aggregates in multiple places. Aggregate roots are supposed to encapsulate child objects so that there's a single place to enforce business rules for related objects.
You can see this clearly in several places in Evans' "Domain-Driven Design" (a.k.a., "The Blue Book"). For example, see the diagram on page 127 (in the introduction to aggregate roots), which shows a Car aggregate that has a reference to an Engine aggregate.
This is only an example.
Say that you have 2 entities for 2 different context boundaries. The first context is the SkillContexter, the entity is 'Player' and has 3 properties: Id, Name and SkillLevel. In the other context (Contactcontext) the entity is 'Player' and has 3 properties: Id, Name and EMail.
How do I persist these entities to the database? I only want one table (Player) and not two tables (PlayerContact, PlayerSkill). Shall I have two different repositories for player that save the different context-entities, but into same table? Or shall I have a "master" player entity that holds all properties that I need to save, so that I create a new entity called PlayerMaster that has 4 properties: Id, Name, EMail and SkillLevel?
The first solution gives me more repositories, and the second makes me make a "technical" entity that only purpose is to save data to a database, and that feels really wrong, or is there a better solution that I have missed?
How have you guys solved it?
When I first started with DDD, I also wrestled with the Context + Domain + Module + Model organization of things as well.
DDD is really meant to be a guide to building your domain models. Once I stopped trying to sub-organize my Contexts and boundies, and started thinking of what really is shared between entities - things started to fit together better.
I actually do not use contexts, unless it is a completely different application (app = context). Just my preference. But, I do have Modules that only share base abstracts and interfaces common throughout code (IRepository, IComponent, etc). The catch is, DDD says that Modules can share entities between modules - but, only on a very limited scale (you really don't want to do it often).
With that in mind, I would get away from using contexts and move to a "what really am I trying to accomplish, what do these models have in common). Here's what I would think, reading your question (if I understand them).
Person() is a base entity. It has ID and Name.
PlayerSkill() is a Value Object, that is
accessable from Person().PlayerSkill.
Contact() is an entity that inherits Person(),
so it inherits ID and Name, and has additional Contact properties you want.
Now, I just tore up your domain. I know.
You can use a hybird approach as well:
Person() is a base entity. It has ID and Name.
Player() inherits Person(), applies Skill()
and other VOs.
Contact() inherits Person(), applies Address()
and other VOs.
I'm not quite sure what you mean by context boundaries, so my answer may be off.
Do the two Player entities represent the same physical entity (person)? If so, then I would create a single Player entity with all four attributes and store their data in a single table.