I was working on a UML class model and (basic as it is) I feel I need to see if my assumption is right. I have two types: Administrator and Location. (A relationship exists between the two where an Administrator can be at one or more locations).
An Administrator needs to assign themselves to a Location. Should this assignment operation be in the Location type or the Administrator type? What is the reasoning for one over the other?
As I see it, the Administrator would be the class having a state, and thus knowing where he is. The location is a data-entry, and should be stateless.
Hence, it's the administrator where you would add or remove locations.
Ie. typical C#:
Administrator.Locations.Add
Administrator.Locations.Remove
Also, I don't see how it could in the Location type, without you using two-way relations, which doesn't seem appropriate here.
Both are possible and with argumentation, both could also be just fine.
If the administrator is logged in at the main server, he could invoke AdminUtils.Locations(That).AddAdministrator(Me). On the other hand, if the administrator is at a specific location he could, prior to logging in at that location, invoke AdminUtils.Administrators(Me).AddLocation(This).
These kind of questions are for specific situations generally answered by considering responsibilities. Which entity is responsible for which entities?
Also note that these Add methods could perfectly be elements of both entities, but one of them is mapped to the actual storage which should be just one.
It depends on what is your software about. If it's a database about people, then Administrator will contain list of assigned places(addLocation / removeLocation), if it's about places, then Location should reference its Administrator(setAdministrator). If you track the history of assignments then obviously Assignment will be a separate entity.
Such things are very well described in DDD Book by Eric Evans
Related
I have been trying to get started on Domain Driven Design (DDD) and therefore I've been studying it for a while now. I have a problem and I seek help around how I can solve it in a DDD fashion.
I have a Client class, which contains a hell lot of attributes - some of them are simple attributes, such as string contactName whereas others are complex ones, such as list addresses, list websites, etc.
DDD advocates that Client should be an Entity and it should also be an Aggregate root - ie, the client code should manipulate only the Client object itself and it's down to the Client object to perform operations on its inner objects (addresses, websites, names, etc.).
Here's the point where I get confused:
There are tons of business rules in the application that depend on the Client's inner objects - for instance:
Depending on the Client's country of birth or resident and her address, some FATCA (an US regulation) restrictions may be applicable.
I need to enrich some inner objects with data that comes from other systems, both internal to my organisation as well as external.
The application has to decide whether a Client is allowed to perform an operation and to that end, the app needs to scrutinize a lot of client details and make a decision - also, as the app scrutinizes the Client it needs to update many of its attributes to keep track of what led the application to that decision.
I could list hundreds of rules here - but you get the idea. My point is that I need to update many of the Client's inner attributes. From the domain perspective, the root is the Client - it's the Client that the user searches for in the GUI. The user cares only about the Client as a whole. Say, an isolated address is meaningless - it only exists if it's part of a Client.
Having said all that, my question is:
Eric Evans says it's OK for the root to return transient references to inner objects, preferably VOs (keyword here: VO) - but any manipulation on the inner objects should be performed by the root itself.
I have hundreds of manipulations that I need to perform on my clients - if I move all of them to the root, the root is going to become huge - it will have at least 10K lines of code!
According to Eric, a VO should be immutable - so if my root returns VOs, the client code won't be allowed to change them. So doing something like this would be unacceptable in a service: client.getExternalInfo().update(getDataFromExternalSystem())
So my question boils down to how on Earth I should update the inner objects without breaking the DDD rules?
I don't see any easy way out.
UPDATE I:
I've just come across Specifications, which seems to be the ideal DDD concept to my problem.
I'm still reading about it but I have decided to post this update anyway.
I have been studying DDD for awhile myself and am struggling to master it.
First, you're right: Specification is a fine pattern to use for validation or business rules in general, assuming the rules you are applying fit well with a predicate tree.
Of course, I don't know the specifics of your design, but I do wonder about the model itself. You mention that your Client class has "a hell lot of attributes". Are you sure your model is not somewhat anemic? Could your design benefit from some more analysis, perhaps breaking it out into other Aggregates? Is this a single Bounded Context? Should it be?
Specifications is definitely the way to go for complex business logic.
One question though - are you modeling the inner entities like addresses and names as ValueObjects? The best rule of thumb I can think of for those is if you can say they're equal, without an ID, they're likely value objects. Does your domain consider names to have a state?
If you're looking at a problem where few entities take in many types of change AND need an audit trail, you might want to also explore EventSourcing. Ideally the entity declares its reaction to an event, but you can also have the mutating code be held in the event for easy extensibility. There's pros and cons in that approach, of course.
I have two classes, Server and Application, with a many-to-many relationship: a server can run multiple applications, an application can run across multiple servers. A third class, Host, represents a single application on a single server, including references to the Application and Server objects as well as additional data such as the amount of disk space used by the application on the server. Both Server and Application objects contain a list of all their hosts: hence, Applications know about Hosts and Hosts know about Applications, and Servers know about Hosts and Hosts know about Servers.
The purpose of my project is to work out the schedule for migrating a bunch of applications onto new servers. Originally each application had a migration-start and migration-end date. Some applications also have start and end dates for virtualisation. Virtualisation occurs if the migration cannot be performed within the application's constraints (never mind what these are). It occurs prior to the migration and frees the application from its constraints. An object called 'Schedule' is held by the Application object, which includes these 4 dates as well as a boolean flag to say whether it is to be virtualised, and a list of 'months' which contain the man-hours required to migrate (or virtualise) the application in each particular month.
We now want to allow servers to undergo virtualisation separately, on a specified date. All the applications (or parts of applications, i.e. hosts) on these servers will be virtualised on this date; they will be migrated along with the rest of the application. We originally decided to have the server class hold its own Schedule object. The virtualisation dates were then set in the server. However, we decided we wanted to keep the server and application schedules consistent - so that, for example, the server schedule's migration-start and end dates should be set to the earliest start and latest end dates, respectively, of all applications running on that server. This meant that every time we updated the Application dates, we had to remember to update all its server dates (via the host object). Or, if we wanted to update the Application's man-hours for a particular month, we had to update the server's man-hours also.
Then we thought about putting a single Schedule object inside each Host object. This solves the consistency problem, but leads to quite a bit of redundancy: since all Host objects belonging to an application will necessarily have the same migration dates (but possibly different virtualisation dates), when you set the migration dates for an app, you have to set the same dates for every host. Also, there are a few instances where we need to work out the earliest-start and latest-finish dates for servers AND applications, as above. This would involve either: holding this data in each of the application and server objects (effectively giving each its own Schedule, thereby brining back problems with consistency), or: calculating this data on-the-fly each time it is needed, by looping through all the hosts' schedules. The same goes for the man-hours required by an application each month, which is calculated at the application level, fractioned into hours for each host per month, and then recalculated when we need to figure it out at the application level again. This is, as you would expect, not efficient in the slightest.
This isn't a straightforward question, but I'm wondering if there are any accepted strategies for dealing with this sort of situation. Sorry in advance for the prolixity of my post; hopefully I've made the situation clear enough.
This is complex once we get into 3rd paragraph onwards
I will use the following design principle
Keep Application, Server, Host objects contain the minimum required behaviors and states.
For example, Application Object may contain start date, end date and virtualization start and virtualization end dates. Think whether it require to contain a list of servers? or instance of Host?
Then a think about a small frame work like this.
a) MigrationManager who does the complete process of Migration using List
b) MigratioContext will composite information for migration process.
c) ErrorContext will composite the error and exception handling
Migration Manager gets an instance of Scheduler and schedules the migration
In this way we can gradually evolve a frame work kind of stuff around the core business object and business logic.
The important thing to remember
Separation of Concerns.
Reusability of Code: For exmple Your Application object may not be required to tied up the whole migration process. Instead those things can be done by another object
(This answer is based on my high level understanding and assumptions that could be wrong. But I think you may get some directions to build the application to meet the requirements)
Once more suggestion I have. Use a Modeling Tool such as StarUML or ArgoUML to put your ideas in a pictorial form. This will help all of the members to get into the question very quickly.
Thanks
I think a fundamental principle of object-oriented programming is that to the extent possible, every mutable aspect of state should at all times have exactly one well-defined owner (that owner may, in turn, be owned by exactly one other entity, which is in turned by one other entity, etc.). Other objects and entities may hold references to that mutable state, but any such references should be thought of in terms of the owner. For example, if a method accepts a reference to a collection and is supposed to to populate it, the method would not think in terms of operating on a collection it owns, but rather in terms of operating on a collection owned by someone else, for the benefit of that entity.
Sometimes it is necessary to have various objects to have separate copies of what is supposed to be the same mutable state. This situation frequently arises in things like graphical user interfaces, where an object might "own" the rotational angle of an object, but a display control might need to cache a private rendering of that object in its current orientation. Handling of such cases may be greatly simplified in cases where one object is designated the absolute master, and it keeps other objects notified of its state. It will be greatly complicated if there are multiple objects, none of which has exclusive ownership, but all of which are supposed to nonetheless keep in sync with each other.
If you can work your model so that no piece of state needs to be duplicated, I would highly recommend doing so. It's crucial, though, that your model be capable of representing all scenarios of interest, including the possibility that two things which are supposed to be in the same state, might not be. What's most important is that every aspect of state has a well-defined chain of ownership, so that when an aspect of state is changed, one can say whose state is affected.
I have come into the habit of hand-sketching various diagrams for software I create. My software is mostly for the web. I use E-R diagramming for the data logic (model of MVC) , and a personally invented diagram style for the interactions -- what pages lead to which other ones and what do they do, i.e. the views & controllers of MVC. This allows me to simplify the important concepts, eliminate the inconsistencies and highlights problem areas that need further investigation.
Now, I've been starting to look at an application that requires a fairly complicated system of permissions. Not really "big" -- just complicated -- with several permission "dimensions" where some permissions need to be created on the fly, and some be static.
I find myself wishing there was some simple way to diagram the permissions system, so that I can get the ideas out of my head in a clear form, and make sure there are no inconsistencies. Hence my question:
Has anybody seen/used any method of modeling permissions in a visual diagram?
The 'ls' command uses color to denote permissions.
Also I would think on a whiteboard or powerpoint, that since permissions link groups of users to files, that lines between the two or spatial grouping becomes a possibility.
I would model:
my users with their attributes on the one hand
my resources with their attributes on the other
Identify the key attributes (building blocks). Then start writing bullet-point rules e.g.:
managers in finance can approve up to X
managers in HR can edit employee records...
employees in HR can approve new accounts
What you're doing is building your authorization policies. Then you can consider factoring out parameters e.g. the department attribute / value.
From there, you want to build a tree/flow where the root would be the entry point, the level below would be the departments, the level below other attributes...
Example:
If the user is in purchasing{}
Else if the user in finance{}
Else if...
(but in a graphical tree-based way).
I use XACML for authorization which is policy/tree-based. You can then apply CSS to it (or XSLT) to get a graphical sense of the authorization. Check out my blog for samples: http://www.webfarmr.eu/2010/11/xacml-102-pimp-my-xacml-css/
Hopefully, this fictitious example will illustrate my problem:
Suppose you are writing a system which tracks complaints for a software product, as well as many other attributes about the product. In this case the SoftwareProduct is our aggregate root and Complaints are entities that only can exist as a child of the product. In other words, if the software product is removed from the system, so shall the complaints.
In the system, there is a dashboard like web page which displays many different aspects of a single SoftwareProduct. One section in the dashboard, displays a list of Complaints in a grid like fashion, showing only some very high level information for each complaint. When an admin type user chooses one of these complaints, they are directed to an edit screen which allows them to edit the detail of a single Complaint.
The question is: what is the best way for the edit screen to retrieve the single Complaint, so that it can be displayed for editing purposes? Keep in mind we have already established the SoftwareProduct as an aggregate root, therefore direct access to a Complaint should not be allowed. Also, the system is using NHibernate, so eager loading is an option, but my understanding is that even if a single Complaint is eager loaded via the SoftwareProduct, as soon as the Complaints collection is accessed the rest of the collection is loaded. So, how do you get the single Complaint through the SoftwareProduct without incurring the overhead of loading the entire Complaints collection?
This gets a bit into semantics and religiosity, but within the context of editing a complaint, the complaint is the root object. When you are editing a complaint, the parent object (software product) is unimportant. It is obviously an entity with a unique identity. Therefore you would would have a service/repository devoted to saving the updated complaint, etc.
Also, i think you're being a bit too negative. Complaints? How about "Comments"? Or "ConstructiveCriticisms"?
#Josh,
I don't agree with what you are saying even though I have noticed some people design their "Web" applications this way just for the sake of performance, and not based on the domain model itself.
I'm not a DDD expert either, but I'm sure you have read the traditional Order and OrderItem example. All DDD books say OrderItem belongs to the Order aggregate with Order being the aggregate root.
Based on what you are saying, OrderItem doesn't belong to Order aggregate anymore since the user may want to directly edit an OrderItem with Order being unimportant (just like editing a Complaing with its parents Software Product being unimportant). And you know if this approach is followed, none of the Order invariants could be enforced, which are extremely important when it comes to e-commerce systems.
Anyone has any better approaches?
Mosh
To answer your question:
Aggregates are used for the purpose of consistency. For example, if adding/modifying/deleting a child object from a parent (aggregate root) causes an invariant to break, then you need an aggregate there.
However, in your problem, I believe SoftwareProduct and Compliant belong to two separate aggregates, each being the root of their own aggregates. You don't need to load the SoftwareProject and all N Complaints assigned to it, just to add a new Complaint. To me, it doesn't seem that you have any business rules to be evaluated when adding a new Complaint.
So, in summary, create 2 different Repositories: SoftwareProductRepository and ComplaintRepository.
Also, when you delete a SoftwareProduct, you can use database relationships to cascade deletes and remove the associated Complaints. This should be done in your database for the purpose of data integrity. You don't need to control that in your Domain Model, unless you had other invariants apart from deleting linked objects.
Hope this helps,
Mosh
I am using NH for another business context but similar entity relationships like yours. I do not understand why do you say:
Keep in mind we have already
established the SoftwareProduct as an
aggregate root, therefore direct
access to a Complaint should not be
allowed
I have this in mine, Article and Publisher entities, if Publisher cease to exist, so do all the dependent Artcle entities. I allow myself to have direct access to the Article collections of each Publisher and individual entities. In the DB/Mapping of the Article class, Publisher is one of the members and cannot accept Null.
Care to elaborate the difference between yours and mine?
Sorry this is not a direct answer but too long to be added as a comment.
I agree with Mosh. Each ones of these two entities has its own aggregate root. Let me to explain it in the real life. suppose that a company has developed a software. There are some bug in this software, that made you annoy. you are going to go to the company and aware them from this problem. this company gives you a form to be filled by you.
This form has a field - section - indicates to the software name and description. additionally, it has some parts for your complaint. Is this form the same as the software manual? No. It is a form related to the software. It is not the software. Does this form has any ID? yes. It has. In other words, you can call the company in the next day and ask the operator about your letter of complaint. It is obvious that the operator will ask you about the Id.
This evidence shows that this form has its own entity and it could not be confused with the software itself. Any relation between two different entity does not mean one of them belongs to the other.
Update Edited to reflect clarifications requested by Chris Holmes below. Originally I was referring to a Terminal as a Site but changed it to better reflect my actual domain.
At heart, I think this is a question about modeling a many to many relationship between two root entities where the relationship itself carries some semantic meaning.
In my domain
You can think of a Terminal as a branch location of our company
A Terminal can have a relationship with any number of customers
A customer can have a relationship with any number of terminals (standard many to many)
A customer\terminal relationship means that a customer can potentially store products at the Terminal
This relationship can be enabled\disabled. To be disabled merely means you are temporarily not allowed to store product, so a disabled relationship is different from no relationship at all.
A customer can have many Offices
A Terminal that has a relationship with a customer (enabled or not) must have a default office for that customer that they communicate with
There are some default settings that are applied to all transactions between a Customer and a Terminal, these are set up on a Terminal-Customer Relationship level
I think my objects here are pretty clear, Terminal, Customer, Office, and TerminalCustomerRelationship (since there is information being stored specifically about the relationship such as whether it is enabled, default office, ad default settings). Through multiple refactorings I have determined that both Terminal and Customer should probably be aggregate roots. This leaves me with the question of how to design my TerminalCustomerRelationship object to relate the two.
I suppose I could make the traversal from Terminal to TerminalCustomerRelationship unidirectional toward the relationship but I don't know how to break the relation from the relationship to the customer, especially since it needs to contain a reference to an Office which has a relationship to a Customer.
I'm new to this stuff and while most of DDD makes perfect sense I'm getting confused and need a fresh outlook. Can someone give me their opinion on how to deal with this situation?
Please note that I say Relationship not relation. In my current view it deserves to be an object in the same way that a Marriage would be an object in an application for a wedding chapel. Its most visible purpose is that it relates two objects, but it has other properties that rightfully belong to it as well.
By your description, you definitely need a "TerminalCustomerRelationship" entity to track the associated information. I would also convert the 'IsEnabled' flag into a first class 'Event' entity with a timestamp - this gives you the ability to save a history of the state changes (a more realistic view of what's happening in the domain.)
Here's a sample application (in VS2008) that refects your problem. You can tweak/test the code until the relationships make sense. Run "bin/debug/TerminalSampleApp.exe" and right-click "Terminal->Create Example" to get started.
Let me know if you find it useful.
Names can often clarify an object's responsibilities and bring a domain model into focus.
I am unclear what a Site is and that makes the entire model confusing, which makes it difficult for me to offer better advice. If a Site were a Vendor, for instance, then it would be easy to rename SiteCustomerRelationship as a Contract. In that context it makes perfect sense for Contract to be its own entity, and have the the model look like Vendor-Contract-Customer-Office.
There are other ways to look at this as well. Udi has a decent post on this sort of many-to-many relationship here.
You should not have a object Like SiteCustomerRelationship, its DB specific.
If its truly DDD you should have a Relation like:
Aggregate<Site> Customer.Site
IEnumerable<Aggregate<Office>> Customer.Offices
and perhaps
Aggregate<Office> Customer.DefaultOffice