I have an entity called Person. It represents a person that may share information with other persons. I also define two entities TelephoneNumber and Address, that represents some information. Each person may provision the database with their telephone number and address, as instances of TelephoneNumber and Address, and the information provisioned belongs only to that person. Then, a person that owns a certain information telephone number and address may associate these with each other through the entity Association, and may share this association to other persons.
I'm trying to follow domain driven design methodology. Since a telephone number or address belongs to only one person, the identities of TelephoneNumber and Address are local to this Person's identity. So, I think there is an aggregate that includes the entities Person, TelephoneNumber, Address and Association. The root of the aggregate would be the entity Person. So, obviously I need a repository for the entity Person, since it is the aggregate root, and I can "reconstitute" a person element from a data store using this repository.
Now, a certain person wants to add a telephone number and address, and wants to associate them. So, assuming the person already exists in the data store, I get the Person in question using the repository. How do I then add the information?
I see two approaches. Using addTelephoneNumber and addAddress methods in the Person entity, or using repositories for TelephoneNumber, Address and Association.
Assuming the first approach is the correct one, what do these methods have to do? How may these methods add information to the data store? I precise that I've chosen a traversal direction for the associations between Person and TelephoneNumber/Address, from TelephoneNumber/Address to Person. So, each time I retrieve a Person, I don't retrieve all its phones and addresses.
In this case, when a person wants to add a phone using the addTelephoneNumber method, what the method does? Where the new phone is put?
PS: The telephone numbers and the addresses owned by a person are not necessarily those of this person, they are just information that this person knows and wishes to share with other persons.
The notion of an object encapsulating a phone number and an address seems important in your domain, so you could have something like a ContactInfo entity ("Association" seems a bit too vague) containing a PhoneNumber and an Address. Phone and address don't really "change" per se -it's rather the ContactInfo that changes, so you could make them value objects.
Person would remain the aggregate root and the only entity to have a Repository. You'd just call person.AddContactInfo() to add a new contact info and contact infos would be persisted later together with the person.
Related
I need some clarification on modelling a user for Identity and access domain. The user domain model has a contact information entity (entity because it is mutable), the customer can register with a phone number, but can choose to change it when needed.
The phone number once used by a customer can never be used by any other user. So the model I believe must allow querying the phonenumber table(since it is many to one with the customer, as the old numbers are deactivated and archived).
If creating a domainservice is ok, what should be the Repository as there is no aggregate identified.
With these cases I have a customer(user) aggregate, but to allow querying all the users to see if the phone number provided by the customer is already been used by anyone else, what should be the aggregate, or can I write a DomainService that just can query the database directly to the phonenumber table to check for the uniqueness, am I violating any DDD principle doing so, what are the cleaner alternatives.
An alternative would be to create an Aggregate that makes it explicit in which scope you intend the unique constraint to hold.
As a (contrived) example, a phone number might be unique across a country but not internationally. Thus :
// An Aggregate Root
public class Country {
// Store a lookup structure (userId, phoneNumber) here
public void addUser(userId, phoneNumber) {
// check phone uniqueness here
}
public void changeUserPhone(userId, phoneNumber) {
// check phone uniqueness here
}
}
Since you're using CQRS, phone numbers being in a separate Aggregate doesn't matter because on the Query side, Read Models will reassemble the User and their phoneNumber together.
This also plays well with the "don't create Aggregate Roots" approach since you have a starting point from where to create your User (User is probably an AR) and not just create it out of thin air.
You could have your repository check if the phone number exists, if it does then throw a rule exception else save the change. The key here is to inject an instance of the repository through the application layer and run rule inside the domain layer.
I just started learning about domain driven design, and one of the few things that confuse me the most is how to determine which one should be entity, which one should be value object
I know to determine entity/value object, we need to base on the domain context, in one context, one domain object can be entity, in another, it can be value object, but still there are some situations I can't decide
.e.g. address
- In the context of a customer management application (let's just say an application to manage customers, add/delete/change status,etc of customers), address is clearly value object because here we don't need to differentiate between one address from another, 2 customers can have same address
- On the other hand, in the context of a online booking application, can I say address is an entity? because now we need to differentiate customers by their billing address (just ignore the case 2 customers having same address for the moment)
To me, address is unique itself, so it definitely already has identity. So identity of a domain object will not decide whether it's an entity or value object, if so then what will be the key factors to choose?
Another example, I have one application that list a number of areas in one country, user can choose one area, and find all the restaurants that fit their searching criteria in that area. In this case, is area a value object or entity? Currently I think it's more on an entity but still not very sure. Each area is unique also
I'm not sure whether my question is clear or not, I try my best to explain my thinking currently
I think some of your difficulties may be in the subtle meanings of some of these terms. For example, you mention "To me, address is unique itself, so it definitely has identity". In terms of how most people use "identity" in domain-driven design, your statement would probably be incorrect.
A value object's set of attributes is its definition. If you change any aspect of it, you have a completely different object. Using your address example, if you change any part of it, you get a entirely different address. It is not the same address with aspects of it changed. Your customer moved to a new address; they did not change aspects of the same address.
However, if you were a mapping application and the address itself changed, then here, the address would be a entity. In such a scenario, the city planners may want to re-number houses on the street. In that case, the SAME address is being modified. In that case, we would need to update the entity, not a value object.
Regarding your billing address example, the billing address is probably still a value entity (at least the physical address portion of it). A payment method (e.g. credit card) may be the entity in that example, and it may include other value objects (such as billing address, credit card number, etc).
You may find it helpful to see review this question and its answers as well: Value vs Entity objects (Domain Driven Design)
Hope this helps. Good luck!
Suppose a Person object may have many Addresses but must have one
Do you favor making the one required Address explicit in the object model? If so, any implementation tips?
Cheers,
Berryl
Person{
Address TheRequiredAddress {get;}
IList<Address> OtherAddresses {....}
}
I like this question. As with most design decisions, this is contextual. How will this be used.
Assume I have a primary address in Seattle and a summer house in Phoenix, and a PO box for business purposes. Will my primary address have special priority over my other addresses, or is the choice of address arbitrary? Will you try to locate me in Seattle before you try my summer house or my PO box?
In the case where the primary address is treated differently, I would store it in an explicitly separate location. Otherwise, store them in an arbitrarily ordered collection and enforce the requirement for at least one within the class implementation.
I have Person aggregate in which Address is part and vo , but now i have another aggregate Payment which have another VO PaymentInfo , which contains details like Creditacard number and other details, but now i need Billing Address and Shipping Address in PaymentInfo VO. Now since Address is integral to Person i cannot use that.
So what i do ,
Create separate Address Vo in Payment aggregate and use it as billing address and Shipping Address.
Move address in to separate aggregate and reference it in PaymentInfo and Person.
Create two addresses in Person itself and reference it in PaymentInfo Vo.
help me please ?
Important thing here is - value objects have no identity.
That means - they can become shared between entities easily.
With that I mean - not particular instances should be shared, but their classes, type Address instead of "UK, London street 'whatever' 16". Value object instances should never be shared (again - cause they got no identity and their state is what defines them).
So in Your place - I would make sure Address as a concept is mutually ubiquitous for person and for payment info (they must have same structure), move it into right folder/namespace so I could see that it's shared and use it for both entities.
If they aren't ubiquitous, I would rename Address as PersonAddress and create second one - PayerAddress (name might differ according to Your business You are modeling).
Quoting Jeff from provided link:
There's no problem with 2 aggregate roots referencing the same entity - they just can't reference another aggregate's internals. It is different for value objects, which are simpler. Consider how you can reference dates, like "August 20th, 2010," any number of times in your classes.
i will go with ubiquitous nature of it. Dont reference the Person address class to the billing address and the shipping address..
Two things Can be achieved easily .one is the communication benefit which you can get in the business analyst and second is the Coding will be explicit and understandable.
I'm facing a typical DDD problem. It must be very basic. I have an order and customer.
A customer can create multiple orders. Customer is the root of its own aggregate. Order is the root of its own aggregate. But when a customer creates an order, we display some portion of the customer information on the order. Should Order aggregate hold reference to customer?
When it holds it then when the Order Repository gets the order, we are able to retrieve some portion of customer information as well for display. But when we involve the order in a transaction, customer also gets into it which is creating problem if the customer is also getting updated at the same time. Please advise guys ! My gut feeling says I MUST not hold reference to customer from order.
Question 2: (NEW)
Can I get and hold a reference to the Customer (from Customer Repository) for a given Order while creating an Order (using Order Factory) and safely save the Order (without updating the Customer inside in anyway, Customer is there only for information/query?) without creating contention if the same Customer is getting modified else where? Lets assume NHibernate as ORM.
A simple answer will be that you hold the ID of the customer or, if needed for your domain some ValueObject with a minimal set of information about the customer ( ID, Name ).
A more complex answer is to think about Bounded Context. See Eric Evans's presentation where he wishes he had put the BC chapter as the first chapter in the book.
The idea is that in your Customer Management Bounded Context, your Customer entity can be the AR of the Customer Aggregate and the Orders can be entities in the Customer Aggregate. In the Billing Bounded Context you can have an Order AR with a Customer entity inside.