Designing a class diagram for a domain model - uml

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.

Related

How to lower redundancy in my UML Class diagram?

I am modeling a course management system with the following requirements:
2 roles: Student can choose course; Administrator can make courses and then make groups for course, based on list of students who chose that course and based on list of tutors for that course.
In one course students can go only in one group, and teacher can teach more groups in one course. But student can go in 1 or more courses.
This diagram is a sketch of a class diagram. There is too much redundancy and I don't know how to solve it. Please help me to model my domain and ignore the mistakes in UML syntax or multiplicitycardinality.
More precisely, how can I make association between students and groups, and tutors and groups without redundancy, because I already have associations with courses?
Let's focus indeed on the domain model:
The direct association between Student and Course corresponds to the student's choice. The choice may or may not be fulfilled. And if it is fulfilled, it's only when the groups are made.
The indirect association between Student and Course via Group corresponds not only to fulfilled choices, but also to practical organisation of courses.
The two paths that exist are not redundant, but the representation of two different realities.
For the tutor, it's similar: the direct association tells what the tutor is able to do, and the indirect one tells what he/she has to do. So the model looks fine in this regard.
In some cases you could simplify (hint: not here)
In some situation a choice/plan can be combined with a fulfilled choice/implementation, by merging associations. For example, if there wasn't your group requirement, you could have only one association class between Student and Course and use a state of your association class to make the difference. But this will not work here, given your requirements.
You could also trick with the requirements. For example, you could have for every course a dummy group that corresponds to students that chose the course and are not assigned to a group. But shortcuts in the design can (and often will) backfire. Here for example, it would add complexity (need to create a dummy group for every course, make a difference between the dummy group and the real groups in almost every activity). Moreover, this trick would constrain your solution. For instance, not having an association class for the choice will prevent from enabling the students to prioritise their courses or providr other elements that facilitate the creation of groups that do not yet exist (e.g. pre-existing skill level).
In summary: your model should primarily aim at addressing the requirements. Premature optimisation is the root of all evil, in modelling as well.

What is an Aggregate Root?

No, it is not a duplication question.
I have red many sources on the subject, but still I feel like I don't fully understand it.
This is the information I have so far (from multiple sources, be it articles, videos, etc...) about what is an Aggregate and Aggregate Root:
Aggregate is a collection of multiple Value Objects\Entity references and rules.
An Aggregate is always a command model (meant to change business state).
An Aggregate represents a single unit of (database - because essentialy the changes will be persisted) work, meaning it has to be consistent.
The Aggregate Root is the interface to the external world.
An Aggregate Root must have a globally unique identifier within the system
DDD suggests to have a Repository per Aggregate Root
A simple object from an aggregate can't be changed without its AR(Aggregate Root) knowing it
So with all that in mind, lets get to the part where I get confused:
in this site it says
The Aggregate Root is the interface to the external world. All interaction with an Aggregate is via the Aggregate Root. As such, an Aggregate Root MUST have a globally unique identifier within the system. Other Entites that are present in the Aggregate but are not Aggregate Roots require only a locally unique identifier, that is, an Id that is unique within the Aggregate.
But then, in this example I can see that an Aggregate Root is implemented by a static class called Transfer that acts as an Aggregate and a static function inside called TransferedRegistered that acts as an AR.
So the questions are:
How can it be that the function is an AR, if there must be a globaly unique identifier to it, and there isn't, reason being that its a function. what does have a globaly unique identifier is the Domain Event that this function produces.
Following question - How does an Aggregate Root looks like in code? is it the event? is it the entity that is returned? is it the function of the Aggregate class itself?
In the case that the Domain Event that the function returns is the AR (As stated that it has to have that globaly unique identifier), then how can we interact with this Aggregate? the first article clearly stated that all interaction with an Aggregate is by the AR, if the AR is an event, then we can do nothing but react on it.
Is it right to say that the aggregate has two main jobs:
Apply the needed changes based on the input it received and rules it knows
Return the needed data to be persisted from AR and/or need to be raised in a Domain Event from the AR
Please correct me on any of the bullet points in the beginning if some/all of them are wrong is some way or another and feel free to add more of them if I have missed any!
Thanks for clarifying things out!
I feel like I don't fully understand it.
That's not your fault. The literature sucks.
As best I can tell, the core ideas of implementing solutions using domain driven design came out of the world of Java circa 2003. So the patterns described by Evans in chapters 5 and six of the blue book were understood to be object oriented (in the Java sense) domain modeling done right.
Chapter 6, which discusses the aggregate pattern, is specifically about life cycle management; how do you create new entities in the domain model, how does the application find the right entity to interact with, and so on.
And so we have Factories, that allow you to create instances of domain entities, and Repositories, that provide an abstraction for retrieving a reference to a domain entity.
But there's a third riddle, which is this: what happens when you have some rule in your domain that requires synchronization between two entities in the domain? If you allow applications to talk to the entities in an uncoordinated fashion, then you may end up with inconsistencies in the data.
So the aggregate pattern is an answer to that; we organize the coordinated entities into graphs. With respect to change (and storage), the graph of entities becomes a single unit that the application is allowed to interact with.
The notion of the aggregate root is that the interface between the application and the graph should be one of the members of the graph. So the application shares information with the root entity, and then the root entity shares that information with the other members of the aggregate.
The aggregate root, being the entry point into the aggregate, plays the role of a coarse grained lock, ensuring that all of the changes to the aggregate members happen together.
It's not entirely wrong to think of this as a form of encapsulation -- to the application, the aggregate looks like a single entity (the root), with the rest of the complexity of the aggregate being hidden from view.
Now, over the past 15 years, there's been some semantic drift; people trying to adapt the pattern in ways that it better fits their problems, or better fits their preferred designs. So you have to exercise some care in designing how to translate the labels that they are using.
In simple terms an aggregate root (AR) is an entity that has a life-cycle of its own. To me this is the most important point. One AR cannot contain another AR but can reference it by Id or some value object (VO) containing at least the Id of the referenced AR. I tend to prefer to have an AR contain only other VOs instead of entities (YMMV). To this end the AR is responsible for consistency and variants w.r.t. the AR. Each VO can have its own invariants such as an EMailAddress requiring a valid e-mail format. Even if one were to call contained classes entities I will call that semantics since one could get the same thing done with a VO. A repository is responsible for AR persistence.
The example implementation you linked to is not something I would do or recommend. I followed some of the comments and I too, as one commenter alluded to, would rather use a domain service to perform something like a Transfer between two accounts. The registration of the transfer is not something that may necessarily be permitted and, as such, the domain service would be required to ensure the validity of the transfer. In fact, the registration of a transfer request would probably be a Journal in an accounting sense as that is my experience. Once the journal is approved it may attempt the actual transfer.
At some point in my DDD journey I thought that there has to be something wrong since it shouldn't be so difficult to understand aggregates. There are many opinions and interpretations w.r.t. to DDD and aggregates which is why it can get confusing. The other aspect is, in IMHO, that there is a fair amount of design involved that requires some creativity and which is based on an understanding of the domain itself. Creativity cannot be taught and design falls into the realm of tacit knowledge. The popular example of tacit knowledge is learning to ride a bike. Now, we can read all we want about how to ride a bike and it may or may not help much. Once we are on the bike and we teach ourselves to balance then we can make progress. Then there are people who end up doing absolutely crazy things on a bike and even if I read how to I don't think that I'll try :)
Keep practicing and modelling until it starts to make sense or until you feel comfortable with the model. If I recall correctly Eric Evans mentions in the Blue Book that it may take a couple of designs to get the model closer to what we need.
Keep in mind that Mike Mogosanu is using a event sourcing approach but in any case (without ES) his approach is very good to avoid unwanted artifacts in mainstream OOP languages.
How can it be that the function is an AR, if there must be a globaly unique identifier to it, and there isn't, reason being that
its a function. what does have a globaly unique identifier is the
Domain Event that this function produces.
TransferNumber acts as natural unique ID; there is also a GUID to avoid the need a full Value Object in some cases.
There is no unique ID state in the computer memory because it is an argument but think about it; why you want a globaly unique ID? It is just to locate the root element and its (non unique ID) childrens for persistence purposes (find, modify or delete it).
Order A has 2 order lines (1 and 2) while Order B has 4 order lines (1,2,3,4); the unique identifier of order lines is a composition of its ID and the Order ID: A1, B3, etc. It is just like relational schemas in relational databases.
So you need that ID just for persistence and the element that goes to persistence is a domain event expressing the changes; all the changes needed to keep consistency, so if you persist the domain event using the global unique ID to find in persistence what you have to modify the system will be in a consistent state.
You could do
var newTransfer = New Transfer(TransferNumber); //newTransfer is now an AG with a global unique ID
var changes = t.RegisterTransfer(Debit debit, Credit credit)
persistence.applyChanges(changes);
but what is the point of instantiate a object to create state in the computer memory if you are not going to do more than one thing with this object? It is pointless and most of OOP detractors use this kind of bad OOP design to criticize OOP and lean to functional programming.
Following question - How does an Aggregate Root looks like in code? is it the event? is it the entity that is returned? is it the function
of the Aggregate class itself?
It is the function itself. You can read in the post:
AR is a role , and the function is the implementation.
An Aggregate represents a single unit of work, meaning it has to be consistent. You can see how the function honors this. It is a single unit of work that keeps the system in a consistent state.
In the case that the Domain Event that the function returns is the AR (As stated that it has to have that globaly unique identifier),
then how can we interact with this Aggregate? the first article
clearly stated that all interaction with an Aggregate is by the AR, if
the AR is an event, then we can do nothing but react on it.
Answered above because the domain event is not the AR.
4 Is it right to say that the aggregate has two main jobs: Apply the
needed changes based on the input it received and rules it knows
Return the needed data to be persisted from AR and/or need to be
raised in a Domain Event from the AR
Yes; again, you can see how the static function honors this.
You could try to contat Mike Mogosanu. I am sure he could explain his approach better than me.

DDD: University as an aggregate root

For some time I am dealing with Domain-Driven Design. Unfortunately I have some problems regarding the Aggregate.
Say, I like to model the structure of an university. The university has some departments (faculties) and every department has some classes. There is a rule that every department needs to be unique and so every class in it. For instance the names of the classes needs to be unique. If I understand it right, then "University" seems to be my aggregate root and "department" and "class" are entities within this aggregate.
There is another aggregate root "Professor", because they are globally accessible. They will be assigned to a class. I´m unsure if it is allowed because an aggregate root should only point to another aggregate root and not to its content.
How to handle this?
Appreciate your help,
thanks in advance!
Say, I like to model the structure of an university. The university has some departments (faculties) and every department has some classes. There is a rule that every department needs to be unique and so every class in it. For instance the names of the classes needs to be unique.
Really? why? What's the business value of that rule? What does it cost the business (the university) if there happen to be two classes with the same name. Does that mean the same name across all time, or just during a given semester?
Part of the point of DDD is that the design of the solution requires exploration of the "ubiquitous language" to get a full understanding of the requirement.
In other words, you may be having trouble finding a good fit for this requirement in the design because you haven't yet discovered all of the entities that you need to make it work the way the business experts expect.
Udi Dahan points out that the uniqueness rule may not belong in the domain at all:
Rules that are not part of genuine domain logic do not have to be implemented in the domain model, suggested he, because they do not model the domain.
So if you have a constraint like this, but the constraint isn't a consequence of the domain itself, then the constraint can be correctly implemented elsewhere.
Greg Young has also written about set validation, specifically addressing concerns about eventual consistency.
But broadly, yes -- if you really have a collection of entities, and a domain rules that span multiple elements in the collection, then you need some aggregate that maintains the integrity of the boundary that the collection lives in.
The entities aren't necessarily what you think. For instance, if you need names to be unique, and the rest of the class entity is just along for the ride, then you may be able to simplify the rules by creating a name registry aggregate; Professors reserve names for their classes, and if the reservation is available, then the reserved name can be applied to the class entity.
If your core business really were naming things, with lots of special invariants to consider, you might build out a big model around this. But that's not particularly likely; perhaps you can just slap a table or two into a relational database -- that's a good solution for a set validation problem -- and get on with the valuable part of the project.
There is another aggregate root "Professor", because they are globally accessible. They will be assigned to a class. I´m unsure if it is allowed because an aggregate root should only point to another aggregate root and not to its content.
class.assign(professorId);
is the usual sort of answer here -- you pass around the surrogate key that identifies the aggregate root. Every entity in your domain should have one.
A couple of cautions here: I have found that real world entities (people, in particular) aren't a useful starting point for figuring out what aggregates are for. Primarily, because they end up being representations, primarily, of data where the invariant is enforced outside the domain model.
Also, I've found that starting from the nouns - class, department, professor - tends to put the focus on CRUD, which generally isn't a very interesting problem.
Instead, I recommend thinking about doing something useful -- a use case where there are business rules to enforce, when the business model gets to say "no, the business won't let you do that right now".
Ask yourself these questions:
How many universities will be in your system? If this is only one, it is not your aggregate root.
If you have multiple universities in your system, would be someone working across universities? May be universities are your system tenants?
What happens with a class if some department is dissolved? Will it immediately disappear? I doubt it.
The same as above with university to department relationship
It is not a problem with a Department to hold reference to its classes as a list of value objects that will contain the Class aggregate root id and the class name. The same is valid for departments dealing with their classes.
Vernon's Effective Aggregate Design might help too.
I'm not very experienced in DDD either but here some tips I use to use:
Is it possible to have a Class without a Department assigned? If that is the case then the Department is the aggregate root and Class is another aggregate with a reference to the root, the Department. You can even define a factory method "addClass()" within your Department with the info that a Class needs to be created, so nobody should be allowed to create a Class without a Department.
Why defining a Class a an Aggregate instead of a Value Object? Because Value Objects are distinguished by their properties' value rather than an ID. I would say that even having two Classes with the same name, same students, same info, etc, etc. the business would still want to differentiate each one. It is not the same with a 1 cent coin which with you only care about the value (given by the color, size, weight,...) but you can always replace it with another one with same attributes' value, that is 1 cent. Also assigning another Professor to the class, the class remains the same, it is not immutable as a Value Object should be.
I guess a Professor must be uniquely identified, and he can maybe be assigned to different Classes or even Departments. So to me it is another Aggregate root separated from the department.

UML Domain Model of Web Shop

So I'm working on an assignment for school, where I am to model (using a domain model) a web shop that delivers complete grocery bags to people's homes. (http://www.linasmatkasse.se). I wish I could be more specific here, but this is all I have unfortunately.
I haven't received any use case, but the scenario would be something like, add bag to cart, create account/add info, pay.
This is what I have so far : http://i.imgur.com/BIljBtj.png?1
Are there any redundancies? (I only have to depict the model of the site, unsure how much to include).
Could/Should I add composition between for instance Customer and Account, Cart and OrderLineItem, Order and Cart?
Pretty uncertain about attributes & multiplicites in general. Any feedback or support here is appreciated.
Payment class? Is it needed? Should it have payment methods included?
Should I model human elements like support?
Should I model more of the delivery
Is association between customer and order needed?
Thanks a bunch! Again...
It should be a class diagram. So, such verbs as "has", "contains", should be shown as aggregation, "supplies", "describes", "makes" should appear on associations arrows only if these names are the names of the attribute in the source(for arrow) class. "owns" should be shown as a dot on the end of association. Also put attribute names really on ends of the associations. You can name the whole associations, but that implies, that the association itself, without the instances of the classes, somehow exists. If you want to write comments, they are to be placed on the notes. But normally that words as "supplies", "describes", "makes", "has", "contains", "owns", appear on the Use case diagram. Make it apart from the class diagram, if you want to think on this logic or discuss it with a client or a sales manager you work with.
Composition
That one between Account and Cart you have made very nicely. Thus you cay, that Cart doesn't exist out of its Account and any account has only one cart. So, the composition with multiplicity 1 to 1 is sensible and bears a lot of important info.
The customer as you made it, is useless. You need only Account.
Till now I don't understand the use of OrderLineItem and ItemList. If the use of some classes is not obvious, it is bad - at least put comments there or think, if you really need them.
Payment - yes, it is necessary. As for payment methods, put them in the specific Enumeration class block, name them there as items and connect Payment to PaymentMethods.
No human elements here! You are deep into the IT model, on the border of coding. You really want to do a use case diagram, don't you?
Delivery? Maybe more enumerations for way of delivery and supplier, ClientAddress that is seen from Account, Order. It is for you to decide if you want to cover this or that scope.
ItemDescription should be connected to Item only
All you associations are navigable in both ways. It is senseless. Choose the navigability.
If a class attribute is an instance of another class, put a dot on that another end of association (end owned by classifier).
Supplier connected to Order? Do you want to cover the theme of trade with suppliers, too? Then there should be more classes on that theme. And it could be another component and another class diagram. Or is there a graphic error?

Feedback on UML Class Diagram

I am creating a Class Diagram for a simple booking system for the theater. I would like to know if the diagram makes any sense and if anything needs to be changed (arrow directions) in order for it to be correct?
Thanks.
Image URL: http://i.stack.imgur.com/zWiGW.jpg
Here are some recommendations that you're free to incorporate or ignore as you see fit:
I don't agree with the relationship between Show and Venue. It seems more natural to have a Booking maintain the relationship between a Show and a Venue.
I don't see a Date for a Show anywhere. Did I miss it? That seems important.
Shows don't have Seats; a Venue has Seats.
A Ticket ought to entitle you to a Seat in a Venue on a particular date. I don't see that.
TicketType should be nothing but an enum.
Decompose User to have a Name, Address, and Credential classes. Separate the Credentials out from User.
A real payment system would need far more than what you have showing (e.g. CreditCard, etc.)
I think your model needs a lot of work.
In addition to what duffymo said, here are some generic observations not strictly related to this particular diagram but rather you modeling practices.
If an association is one way navigable then there is no need to name both ends. You have named both ends of all associations, but only navigable end needs a name.
Drop the 'can' from all association ends. In some cases there is a handy term, for example show can be hosted at a Venue. But in other cases it's perfectly fine and even common practice to name association ends same as the class at that end. (so name the Seat end simply Seats)
Avoid many to many relationships if you can. If you can't then look into adding an association class in between, it almost always makes sense.

Resources