The principle of always valid domain model dictates that value object and entities should be self validating to never be in an invalid state.
This requires creating some kind of wrapper, sometimes, for primitive values. However it seem to me that this might break the ubiquitous language.
For instance say I have 2 entities: Hotel and House. Each of those entities has images associated with it which respect the following rules:
Hotels must have at least 5 images and no more than 20
Houses must have at least 1 image and no more than 10
This to me entails the following classes
class House {
HouseImages images;
// ...
}
class Hotel {
HotelImages images;
}
class HouseImages {
final List<Image> images;
HouseImages(this.images) : assert(images.length >= 1),
assert(images.length <= 10);
}
class HotelImages {
final List<Image> images;
HotelImages(this.images) : assert(images.length >= 5),
assert(images.length <= 20);
}
Doesn't that break the ubiquitous languages a bit ? It just feels a bit off to have all those classes that are essentially prefixed (HotelName vs HouseName, HotelImages vs HouseImages, and so on). In other words, my value object folder that once consisted of x, y, z, where x, y and z where also documented in a lexicon document, now has house_x, hotel_x, house_y, hotel_y, house_z, hotel_z and it doesn't look quite as english as it was when it was x, y, z.
Is this common or is there something I misunderstood here maybe ? I do like the assurance it gives though, and it actually caught some bugs too.
There is some reasoning you can apply that usually helps me when deciding to introduce a value object or not. There are two very good blog articles concerning this topic I would like to recommend:
https://enterprisecraftsmanship.com/posts/value-objects-when-to-create-one/
https://enterprisecraftsmanship.com/posts/collections-primitive-obsession/
I would like to address your concrete example based on the heuristics taken from the mentioned article:
Are there more than one primitive values that encapsulate a concept, i.e. things that always belong together?
For instance, a Coordinate value object would contain Latitude and Longitude, it would not make sense to have different places of your application knowing that these need to be instantiated and validated together as a whole. A Money value object with an amount and a currency identifier would be another example. On the other hand I would usually not have a separate value object for the amount field as the Money object would already take care of making sure it is a reasonable value (e.g. positive value).
Is there complexity and logic (like validation) that is worth being hidden behind a value object?
For instance, your HotelImages value object that defines a specific collection type caught my attention. If HotelImages would not be used in different spots and the logic is rather simple as in your sample I would not mind adding such a collection type but rather do the validation inside the Hotel entity. Otherwise you would blow up your application with custom value objects for basically everything.
On the other hand, if there was some concept like an image collection which has its meaning in the business domain and a set of business rules and if that type is used in different places, for instance, having a ImageCollection value object that is used by both Hotel and House it could make sense to have such a value object.
I would apply the same thinking concerning your question for HouseName and HotelName. If these have no special meaning and complexity outside of the Hotel and House entity but are just seen as some simple properties of those entities in my opinion having value objects for these would be an overkill. Having something like BuildingName with a set of rules what this name has to follow or if it even is consisting of several primitive values then it would make sense again to use a value object.
This relates to the third point:
Is there actual behaviour duplication that could be avoided with a value object?
Coming from the last point thinking of actual duplication (not code duplication but behaviour duplication) that can be avoided with extracting things into a custom value object can also make sense. But in this case you always have to be careful not to fall into the trap of incidental duplication, see also [here].1
Does your overall project complexity justify the additional work?
This needs to be answered from your side of course but I think it's good to always consider if the benefits outweigh the costs. If you have a simple CRUD like application that is not expected to change a lot and will not be long lived all the mentioned heuristics also have to be used with the project complexity in mind.
Should DDD Repository always return aggregate and all it's value objects and entities?
For an example, I have Invoice object which has it's type and items.
Invoice
--Id
--Issuer
--InvoiceType
--Items
Data are persisted in 4 SQL Tables.
Invoices (FK to invoice type, FK to issuers),
InvoiceTypes
Items(fk to Invoice)
Issuers
If a repository should always return aggregates in it's full state, is it a bit of overkill to include InvoiceType and Items if i need to fetch 50 invoices, and display only ID and IssuerName.
Example for
InvoiceRepository
{
//should this also fetch InvoiceTypes and items from SQL, or i need separate invoice model for this
public List<Invoice> FetchForListing(int page, int take);
}
Should DDD Repository always return aggregate and all it's value objects and entities?
No. In use cases where you are going to be performing a write, you should load everything, because you need the full internal state to ensure that your change satisfies the invariant.
But if you are only going to perform a read, the full state isn't necessary at all -- it's reasonable to limit to the data you pull out.
(For example: when using the cqrs pattern, reads tend to not touch the aggregate at all, but instead copy data from "projections" of aggregate state into a more suitable representation.)
InvoiceRepository
{
// should this also fetch InvoiceTypes and items from SQL,
// or i need separate invoice model for this
public List<Invoice> FetchForListing(int page, int take);
}
So in this case, you wouldn't return a List<Invoice>, since that isn't what you want, and you might not use the same interface to represent the repository
InvoiceSummaryRepository
{
public List<InvoiceSummary> readSummary(int page, int take);
}
Check in your own ubiquitous language to figure out what InvoiceSummary is actually called, to determine whether List<InvoiceSummary> is actually a thing with a name of its own (likely is you are using it to build the representation of a resource in your REST api), and so on.
I am practicing DDD, and I have a very simple example, which looks like this currently:
Polling
getEventBus() -> Bus
getEventStorage() -> Storage
getMemberRepository() -> MemberRepository
getCategoryRepository() -> CategoryRepository
getBrandRepository() -> BrandRepository
getModelRepository() -> ModelRepository
getVoteRepository() -> VoteRepository
MemberRepository
MemberRepository(eventBus, eventStorage)
registerMember(id, uri)
-> MemberRegistered(id, uri, date)
-> MemberRegistrationFailed //when id or uri is not unique
isMemberWithIdRegistered(id)
isMemberWithUriRegistered(uri)
CategoryRepository
CategoryRepository(eventBus, eventStorage) {
addCategory(id, name)
-> CategoryAdded(id, name, date)
-> CategoryAdditionFailed //when id or name is not unique
isCategoryWithIdAdded(id)
isCategoryWithNameAdded(name)
};
BrandRepository
CategoryRepository(eventBus, eventStorage) {
addBrand(id, name)
-> BrandAdded(id, name, date)
-> BrandAdditionFailed //when id or name is not unique
isBrandWithIdAdded(id)
isBrandWithNameAdded(name)
};
ModelRepository
ModelRepository(eventBus, eventStorage)
addModel(id, name, categoryId, brandId)
-> ModelAdded(id, name, categoryId, brandId, date)
-> ModelAdditionFailed //when id or name is not unique and when category or brand is not recognized
isModelWithIdAdded(id)
isModelWithNameAdded(name)
VoteRepository
VoteRepository(eventBus, eventStorage)
addVote(memberId, modelId, vote, uri)
-> MemberVoted(memberId, modelId, vote, uri, date)
-> VoteFailed //when the member already voted on the actual model and when memberId or modelId is not recognized
I'd like to develop here a polling system, so I think we could call this the polling domain. We have members, categories, brands, models and votes. Each member can vote on a model only once and each model have a brand and a category. For example inf3rno can vote on the Shoe: Mizuno - Wave Rider 19 with 10, because he really likes it.
My problem is with the
addModel(id, name, categoryId, brandId)
-> ModelAdded(id, name, categoryId, brandId, date)
-> ModelAdditionFailed //when id or name is not unique and when category or brand is not recognized
and the
addVote(memberId, modelId, vote, uri)
-> MemberVoted(memberId, modelId, vote, uri, date)
-> VoteFailed //when the member already voted on the actual model and when memberId or modelId is not recognized
parts. Let's stick with the ModelAddtion.
If I want to check whether the categoryId and brandId are valid, I have to call the CategoryRepository.isCategoryWithIdAdded(categoryId) and the BrandRepository.isBrandWithIdAdded(brandId) methods. Is it allowed to access these methods from the ModelRepository? Should I inject the container and use the getCategoryRepository() -> CategoryRepository and getBrandRepository() -> BrandRepository methods? How to solve this properly by DDD?
update:
How would you solve this validation in the domain if you'd really need the foreign key constraint and your db engine would not have this feature?
There are 2 hard problems in computer science: cache invalidation, naming things, off by one errors, and attributing quotes.... I'll come in again.
Repository, as used in the ubiquitous language of DDD itself, doesn't normally mean what you are trying to express here.
Eric Evans wrote (the Blue Book, chapter 6).
Another transition that exposes technical complexity that can swamp the domain design is the transition to and from storage. This transition is the responsibility of another domain design construct, the REPOSITORY
The idea is to hide all the inner workings from the client, so that client code will be the same whether the data is stored in an object database, stored in a relational database, or simply held in memory.
In other words, the interface of a repository defines a contract to be implemented by the persistence component.
MemberRepository
MemberRepository(eventBus, eventStorage)
registerMember(id, uri)
-> MemberRegistered(id, uri, date)
-> MemberRegistrationFailed //when id or uri is not unique
This, on the other hand, looks like a modification to your domain model. "registerUser" has the semantics of a command, MemberRegistered, MemberRegistrationFailed look like domain events, which strongly implies that this thing is an aggregate, which is to say an entity that protects specific invariants within the domain.
Naming one of your aggregates "Repository" is going to confuse everybody. The names of aggregates should really be taken from the ubiquitous language of the bounded context, not from the pattern language we use to describe the implementation.
If I want to check whether the categoryId and brandId are valid, I have to call the CategoryRepository.isCategoryWithIdAdded(categoryId) and the BrandRepository.isBrandWithIdAdded(brandId) methods. Is it allowed to access these methods from the ModelRepository?
Assuming, as above, that CategoryRepository, BrandRepository and ModelRepository are all aggregates, the answer is no, no, and no.
No: If your have modeled your domain correctly, then all of the state needed to ensure that a change is consistent with the business invariant should be included within the boundary of the aggregate that is changing. Consider, for example, what it would mean to be adding a model in this thread, while the brand that the model needs is being removed in that thread. These are separate transactions, which means that the model can't maintain the consistency invariant.
No: if the motivation for the check it to reduce the incidence of errors by sanitizing the inputs, that logic really belongs within the application component, not the domain model. It's the responsibility of the domain model to ensure that the parameters of the command induce a valid change to the state of the model; it's the responsibility of the application to ensure that the correct parameters are being passed. The sanity check belongs outside the domain model
That said
No: aggregates in the domain model shouldn't access each other directly; instead of passing in an aggregate, pass in a domain service that represents the query that the domain model needs to run.
Model.addModel(brandId, brandLookupService) {
if (brandLookupService.isValid(brandId)) {
// ...
}
}
This extra bit of indirection removes any ambiguity about which aggregate is being changed within a given transaction. The BrandLookupService itself, under the covers, could well be loading a read only representation of a Brand from the BrandRepository.
Of course, it still doesn't address the concern that the brands could be changing even as the model is referencing the brand. In other words, there's a potential data race in this design because of where the transactions boundaries are drawn.
How would you solve this validation in the domain if you'd really need the foreign key constraint and your db engine would not have this feature?
Two options:
1) Redraw the aggregate boundaries.
If you need the foreign key constraint enforced by the domain model, then its not a "foreign" key; its a local key for an aggregate that contains both bits of state.
2) Change the requirements
Udi Dahan, I think in this talk, pointed out that sometimes the way that the business (currently) runs simply doesn't scale properly, and the business itself may need to change to get the results that they want.
I am not sure what the aggregates are here.
Let's try this a different way - how do we implement this?
For example inf3rno can vote on the Shoe: Mizuno - Wave Rider 19 with 10, because he really likes it.
In your design above, you used a VoteRepository to do this. We don't want to use "repository", because that noun isn't taken from the ubiquitous language. You called this the polling domain earlier, so let's try Poll as the entity. The Poll entity is going to be responsible for enforcing the "one man, one vote" invariant.
So it's going to look something like
class Poll {
private PollId id;
private Map<MemberId,Vote> recordedVotes;
public void recordVote(MemberId memberId, Vote vote) {
if (recordedVotes.containsKey(memberId)) {
throw VoteFailed("This member already voted. No backsies!");
}
recordedVotes.put(memberId, vote);
}
}
And the code to record the vote is going to look something like
// Vote is just a value type, we can create one whenever we need to
Vote vote = Vote.create(10);
// entity ids are also value types that we can create whenever
// we want. In a real program, we've probably done both of these
// lookups already; Poll and Member are entities, which implies that
// their identity is immutable - we don't need to worry that
// MemberId 3a7fdc5e-36d4-45e2-b21c-942a4f68e35d has been assigned
// to a different member.
PollId pollId = PollId.for("Mizuno - WaveRider 19")
MemberId memberId = MemberId.for("inf3rno");
Poll thePoll = pollRepository.get(pollId);
thePoll.recordVote(memberId, vote);
pollRepository.save(thePoll);
From a puristic view, you shouldn't need to access 2 repositories. I say puristic because it might take a while to understand what missing bits of the domain would simplify this.
From the top of my head, I would question myself the following:
Do you need to ensure that those entities exist? (isCategoryWithIdAdded and isBrandWithIdAdded). Depending on your storage engine, can you enforce this (e.g. required foreign key). I think this would be my approach, as it's also faster from a performance point of view.
Can you ensure those entities exist somewhere else? Some DDD implementations assume that data is correct once an Application Service is called.
And last (this might be a bit questionable) can this feature link 2 things even if they don't exist? (what would be the 'damage').
And just a comment... having something in your domain called Model is so confusing, as it's part of the vocabulary of DDD. =D
Basically I have two value objects each representing price. Rule goes one price cannot be greater than other. There might be case when only one of them are specified.
How to enforce this rule and where? Keep two separate objects and when one gets constructed pass other to it? Sounds a bit weird because inverse rule must be applied to other. I do not want to keep both values in one object because I do not need them to be coupled when I use those values.
Value objects rarely exists on their own and are usually aggregated within an entity which is responsible for enforcing it's invariants.
"I do not want to keep both values in one object because I do not need
them to be coupled when I use those values"
If there is a business rule that spans these values then they probably should be part of the same aggregate. The values themselves will not be directly coupled one to the other, but the aggregate would hold both.
Rule goes one price cannot be greater than other. There might be case when only one of them are specified.
If those two prices go really together and change together like price-from / price-to it is also possible to have PriceRange value object that can check those rules.
public class PriceRange
{
public PriceRange(Price from, Price to)
{
// Check all rules here
From = from;
To = to;
}
public Price From { get; }
public Price To { get; }
}
Checking rules in the Aggregate Root can be better
if AR state enforces price rules
if those two prices change separately
I'm starting to play with Domain Driven Design and have a question about ValueObjects :
Can they contains invariants or other specifications ?
Consider an immutable ValueObject :
ValueObject (
prop integer: Int
prop string: String
// Value and copy constructor
// Observers for integer and string
// Equality methods on integer and string value
)
Can I add some invariants such that integer > 0 & < 42. Or do they have to be simple transfer without any logic ?
I hope they can but need a confirmation.
A value object (VO) encapsulates a value and its business requirements . This is its purpose: to model a business concept (with its constraints) which happens to be a simple (not always single) value.
A VO is not a Data transfer object (DTO) precisely because it defines a business concept that is valid only in the containing bounded context, while a DTO is meant to cross boundaries.
Value objects should handle the invariants for the data that they encapsulate, or at least as much of it as they can. I tend to do the following, which is actually similar to entities except for the immutable bit:
Constructors should make sure it is created in a valid state
The VO's state is encapsulated, and all changes to it are done through controlled methods/etc
Because value objects are immutable, method changes return a new value object rather than updating the existing state
Having the value objects own their own business logic really helps clean up the code in the entities that use these value objects. This can become a problem with big aggregates\entities, so look for opportunities to pull this behavior out into value objects.
It also makes unit testing lots of edge cases MUCH easier, as you are testing the value object on its own.
Your entity may need to do validation across multiple value objects before decides a change CAN happen, but then the value object is responsible for the change itself.