I have begun using domain driven design principles but are currently stuck with a specific problem.
I have an Aggregate which has multiple layers of nested child entities as shown below:
public class Aggregate: Entity<AggregateId>, IAggregateRoot {
private readonly List<ChildOne> childOnes;
}
public class ChildOne: Entity<ChildOneId> {
public string ChildOneValue1;
public string ChildOneValue2;
public string ChildOneValue3;
private readonly List<ChildTwo> childTwos;
}
public class ChildTwo: Entity<ChildTwoId> {
public string ChildTwoValue1;
public string ChildTwoValue2;
public string ChildTwoValue3;
}
In a domain service I need to access all values of ChildOne and ChildTwo including their ids.
public interface IDomainService {
public IEnumerable<INotification> Analyze(Aggregate aggregate);
}
However, I cannot return the entities as they are since this would violate the immutability principle.
This got me thinking that my domain model probably might not be optimal, but I cannot see how this can be different since the nested entities never can exist without the respective parent.
Another approach could be to have a single value object which holds all values of a given entity and then return this value object instead of the entity. But then a deep mapping needs to be performed since the domain service needs access to the values of all nested entities.
Any suggestions on to how to approach this?
Any suggestions on to how to approach this?
There are a couple of possibilities.
One is to invert your proposed API - design the domain service to accept immutable values as arguments, and then pass the instance of that service to the Aggregate, rather than the other way around.
public interface IDomainService {
public IEnumerable<INotification> Analyze(IEnumerable<DomainValue> values);
}
If you recall the Visitor pattern from the Gang of Four book, it is a very similar idea.
In some cases, an in-memory state machine might be a reasonable alternative to a stateless domain service. In that case, the API might look like
public interface IDomainService {
public void OnAnalyze(DomainValue value);
public IEnumerable<INotification> Notifications();
}
Another possibility is to design the Aggregate to act as a Collection
public class Aggregate {
// ...
public IEnumerable<DomainValue> YourCleverNameHere();
}
For use cases where you are not changing the state of the Aggregate, just leave the aggregate out of it, and work directly with an immutable in memory representation of the current state.
However, I cannot return the entities as they are since this would violate the immutability principle.
The entites don't need to be immutable. It's only value object that are immutable in tactical design of domain driven design.
As far as entities are aggregates are concerned, you should be able to get/save an aggregate from the repository only using the aggregate root. You should not be able to get/save an entity that is not an aggregate root.
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
a) I'm a bit puzzled whether in most cases we should only have a factory that produces the entire Aggregate or should we also have a factory that creates only the Aggregate root?
b) Should a factory that builds the entire Aggregate build both root and non-root objects by itself or should it delegate the building of non-root entities/VOs to other factories?
Thus, if Aggregate contains 5 different types of non-root entities, should Aggregate factory create these non-root entities by itself or should we have additional five factories ( one factory for each non-root entity ), to which Aggregate factory would delegate the creation of particular type of non-root entity?
Thank you
In Eric Evans' DDD book, page 138, it's written in bold:
Create entire aggregates as a piece, enforcing their invariants.
Then in the next page:
A FACTORY should only be able to produce an object in a consistent
state. For an ENTITY, this means the creation of the entire AGGREGATE
[...]
Concretely, this means that you would only have one factory to create the entire aggregate. There may be other classes (factories) involved in building your non-root entities or value objects, but there is only one factory responsible for creating an aggregate. This factory creates a full aggregate, not just a root object.
The creation of sub-root objects (for example, an OrderItem for an Order) is handled by the root entity itself, so it can enforce variants in a manner invisible to the outside world.
So a typical flow could be:
var newOrder = orderFactory.CreateOrder(customer);
newOrder.AddOrderItem(product, quantity);
A factory might be used within the entity, but it shouldn't be accessed by the outside world.
public class Order
{
private OrderItemFactory _orderItemFactory;
public AddOrderItem(Product product, int Quantity)
{
var newOrderItem = _orderItemFactory.CreateOrderItem(product, quantity);
}
}`
Hi I have a few questions regarding Domain Driven Design and using Factories / Factory Methods.
Per the Domain Driven Design Blue Book (Eric EVan's Book) it states that complex constructors should be encapsulated inside Factories / Factory Methods / Builders so there is a consistent place where you check all the invariants, so my question is regarding this:
Let's say I am developing a magic organizer application where you can make CRUD like operations on magic effects (like a post on a blog + several attributes like effect duration, materials used (list of strings), patter associated with the magic effect) and some of the invariants are that a magic effect must always have a title, a content of the magic effect, a duration and an optional patter and must be published by a user registered in the application.
So since I have quite a few invariants I have a EffectBuilder that builds MagicEffect objects and checks all the invariants.
Is it ok to do something like this in the user class?
public class User {
// Several attributes and business methods
public MagicEffect publishEffect(final String title, final String content, final Long duration, final Collection<String> elements) [
EffectBuilder builder = new EffectBuilder();
builder.withAuthor(this);
builder.withTitle(title);
builder.withContent(content);
builder.withDuration(duration);
builder.withElements(elements);
return builder.build();
}
};
Or should I do something like:
public class User {
// Several attributes and business methods
public EffectBuilder publishEffect() [
EffectBuilder builder = new EffectBuilder();
builder.withAuthor(this);
return builder;
}
};
And somewhere else
User user = userRepository.findById(userId);
MagicEffect effect = user.publishEffect().withTitle(title).withContent(content).withDuration(duration).withElements(elements).build();
userRepository.save(user);
I mean the first example I have a huge method with huge amount of parameters but I make sure all the invariants are set in the effect when it's built, in the other scenario I programatically improve the code readability by having a fluent interface but I canot make sure the invariants are met 100% of the time.
Which is the better approach? Is there a more balanced approach of doing it?
Thanks
Pablo
I think that your second approach is better. The whole point of Builder is to avoid large list of parameters like you have in your first example. Builder is not responsible for enforcing invariants in the object that it builds. Object itself enforces them. I think it is perfectly fine to have an instance of EffectBuilder without Title or with a default title. As long as the MagicEffect itself enforces 'Every effect should have a title' invariant.