Finding aggregate id based on dependency - domain-driven-design

i have a quite messy question since i'm not sure if this is more of global design issue.
I have service which defines some aggregates and those aggregates publish events. Let's pick one aggregate from the service and call it A.
Now, im defining another service which has some aggregate that is supposed to work with the A, lets call the second aggregate B.
When A publishes some event i want to send command to the B (ideally through saga) but im having a hard time calculating appropriate id of B (the A does not know that B exists, therefore the events it publishes does not have any hint on how to calculate the id)
I can think of few possible scenarios:
First one would be statically calculating the ID of B based on the id of A, for example in axon i could do something like some-id-${suffix} so when i receive event from A with some-id i can immediately know that it should be dispatched to some-id-B
Second one would be using the read side? (im not sure how its properly called) and query the thing and try to find B id based on the A id but that seems a little bit of overkill.
Is there anything i could read that would navigate me through possible scenarios and give me a hint how to handle them? Thanks!

From what I understand, you have a relationship from aggregate B to aggregate A. These kind of relationships are normal and they occur all the time.
Note: Since this question is very general and without a context, I may be missing something. If there is a more special case than the one described notify my about it.
This is a great read for aggregate design
Note: Check this video from Martin Fowler before reading the rest of this answer, I strongly suggest it as it explains concepts related to events and commands in great detail.
Note: Because the term entity is also very important, from here on I will not use aggregate anymore, so assume that each entity (Player, User, Game) are root of their own aggregate and is a consistency boundary, so eventual consistency in this case by domain events will be used. I will also ignore CQRS at the moment to avoid having to talk about read side and write side. We will discuss and implement a Model
Let take the example with the game. You have a Player that should represent a User in a Game. The Player entity should reference the Game and User in some way. It can be via a direct reference or by ID. In the case of distributed system it will be by ID. For our example Lets use UUIDs (for example 8d670541-aa51-470b-9e72-1d9227669d0c) for ID's so we can generate them randomly without having to define a schema, auto generate sequencial number (like in SQL databases) or a special algorithm.
Let's say that a User has UserStatistics. So when that when a Player makes scores (for example by killing other players in a shooting game) the UserStatistics entity should be created if not exists and updated. The UserStatistics should reference User by ID also, so we have a dependency from UserStatistics to User.
UserStatistics will look like this:
UserStatistics {
UUID UserID,
uint KillsCount,
uint GamesPlayedCount
}
Because the Player cannot exists without a User, the User should be created first. Because a Player is part of a Game than means that the Game should be created first. Let define some terminology in our Ubiquitous Language. A User 'joins' a Game by becoming a Player in it. Let say that Game will be created by someone else, not Users to avoid having to discuss the situation when the User creates a game and should join it also at the same time etc. Should this happen in the same transaction etc... The Game will be something like a MMO where it is created by someone and regular users can join.
When a User joins a Game, then the Player entity will be created with a userID and gameID. Creating a Player without an userID and gameID is not valid.
Let discuss the problem with Commands and Events. Commands can be Triggered by Events. Let use the Observer Pattern. One Entity will have to observe another Entity for events. In our example this means that the dependency is from UserStatistics (the observer) to User and Player (the subject/message producer). The fact that a specific Command on a UserStatistics will be executed as a reaction to an Event raised from Player and User should not affect the Player or Player in any way. By using an Event to deliberately trigger a special Command in a passive aggressive style is not a very good strategy. Commands can be triggered by a Event, but not only one specific Command can be Triggered. Many different Commands can be triggered and only the dependent Entities, Services or Systems should care about what happens. The Player and User just provide Events.
When a User joins a Game and the Player is created it will reference both entities by ID, so it will look something like this:
Player {
UUID GameID,
UUID UserID
}
Also UserJoinedGameEvent event will be raised from User entity (it cam be raised from Game but we will choose User). It looks like this:
UserJoinedGameEvent {
UUID GameID,
UUID UserID,
UUID PlayerID
}
The UserStatisticsService can subscribe for events and update statistics.
When a User joins a Game, a process of gathering statistics will start and we will update (or create if it doesn't exists) his UserStatistics with how many games the he has played. At the same time when a Player makes a kill we will have to update the statistics again.
StartGatheringUserStatisticsCommand will be triggered from UserJoinedGameEvent event.
Let's add an event PlayerMadeKillEvent that looks like this:
PlayerMadeKillEvent {
UUID UserID,
UUID PlayerID,
UUID GameID
}
UserStatisticsService will subscribe for PlayerMadeKillEvents and update UserStatistics by using PlayerMadeKillEvent.UserID to find the statistics for the specific User.
When a User quits a Game, a UserQuitsGameEvent can be raised and statistics gathering can stop.
In this example we didn't have a specific schema to generate special ID's, we can reference other aggregates that will be created first and then use their ID.

Related

Read model with data from multiple aggregate roots (different contexts)

I'm curious to how to join data from multiple aggregate roots in an read model for an event sourced aggregate root. Can try to take a simple example:
If I have an aggregate root called Cart which supports following events in it's event stream (properties in parentheses - keep in mind this is an simple example):
AddProductToCart(cartId: Int, productId: Int)
RemoveProductFromCart(cartId: Int, productId: Int)
AddUserLicenseToProduct(cartId: Int, productId: Int, userId: Int)
RemoveUserLicenseFromProduct(cartId: Int, productId: Int, userId: Int)
EmptyCart(cartId: Int)
It's ok when projecting read models with data coming from this event stream. I can for example project a cart object which looks something like this:
Cart(cartId: Int, products: List[Product])
Product(productId: Int, userLicenses: List[UserLicense])
UserLicense(userId: Int)
But how does one join data from another aggregate root in another context into this cart projection. For example if I wanted to extend the read model with data from the Product aggregate root which lives in another context. Let's say I would like to extend it with productName and productType.
Take into consideration we are working in an distributed system, where Product and Cart would be live in different services/applications.
I suppose one solution would be to include the data in the commands and events. But that doesn't seem to scale very well if one would have larger read models with data from multiple aggregate roots. Also one has to be able to nuke and rebuild the read model.
I suppose another solution would be to duplicate data from other aggregate roots into the storage of other applications/services/contexts. For example duplicate the productName and productType data into storage owned be the Cart application, but not have it be a part of the Cart event stream. The Cart application would then have to listen to events (e.g. ProductCreated, ProductNameChanged) to keep data updated. I guess this might be a viable solution.
Each bounded context should be loosely coupled. We had a similar issue with two of our contexts. The solution that we found was to use workflows by creating all the communication between contexts in those files. In which we could synchronize the required schemas by subscribing to an event handler. As we used Elixir, the library that we have been used is Commanded, which have its own Event Bus.
But in a distributed systems you can use Apache Kafka. At the end of the day, I think that the easier solution should keep your schemas the cleanest possible (it also going to help you to respect the GDPR compliance) and to manage all your communication through a separate layer by an event handler.
To see this solution in a "real-life" way, I can recommend you a great example repository built with Elixir.
https://leanpub.com/buildingconduit/read
This question also comes up with event-driven architectures and not only event-sourcing. I reckon that you've covered most options in terms of capturing the relevant data from the producer of the event.
Another option would be that an event contain as little data as possible from the related bounded context. At a minimum that would be an identifier. However, in most cases some of the data should be denormalized to make sense. For instance, having the product description denormalized into the Cart and eventual Order would be helpful especially when someone changes the description after I have made my choice. The description may change from Blue pen to Red pen which would drastically alter what I intended to purchase. In this case the Product in your Shopping BC may be represented by a value object that contains the Id along with the Description.
If you now would like to augment the read-only data we are left only with the option of retrieving it from the source BC. This can be done in the read-model using some API (Rest/ACL) and then the data saved. To make it more fault tolerant one may opt for a messaging/service bus infrastructure to handle the retrieval of the additional data and updating of the relevant read-model record.

DDD: where should logic go that tests the existence of an entity?

I am in the process of refactoring an application and am trying to figure out where certain logic should fit. For example, during the registration process I have to check if a user exists based upon their email address. As this requires testing if the user exists in the database it seems as if this logic should not be tied to the model as its existence is dictated by it being in the database.
However, I will have a method on the repository responsible for fetching the user by email, etc. This handles the part about retrieval of the user if they exist. From a use case perspective, registration seems to be a use case scenario and accordingly it seems there should be a UserService (application service) with a register method that would call the repository method and perform if then logic to determine if the user entity returned was null or not.
Am I on the right track with this approach, in terms of DDD? Am I viewing this scenario the wrong way and if so, how should I revise my thinking about this?
This link was provided as a possible solution, Where to check user email does not already exits?. It does help but it does not seem to close the loop on the issue. The thing I seem to be missing from this article would be who would be responsible for calling the CreateUserService, an application service or a method on the aggregate root where the CreateUserService object would be injected into the method along with any other relevant parameters?
If the answer is the application service that seems like you are loosing some encapsulation by taking the domain service out of the domain layer. On the other hand, going the other way would mean having to inject the repository into the domain service. Which of those two options would be preferable and more in line with DDD?
I think the best fit for that behaviour is a Domain Service. DS could access to persistence so you can check for existence or uniquenes.
Check this blog entry for more info.
I.e:
public class TransferManager
{
private readonly IEventStore _store;
private readonly IDomainServices _svc;
private readonly IDomainQueries _query;
private readonly ICommandResultMediator _result;
public TransferManager(IEventStore store, IDomainServices svc,IDomainQueries query,ICommandResultMediator result)
{
_store = store;
_svc = svc;
_query = query;
_result = result;
}
public void Execute(TransferMoney cmd)
{
//interacting with the Infrastructure
var accFrom = _query.GetAccountNumber(cmd.AccountFrom);
//Setup value objects
var debit=new Debit(cmd.Amount,accFrom);
//invoking Domain Services
var balance = _svc.CalculateAccountBalance(accFrom);
if (!_svc.CanAccountBeDebitted(balance, debit))
{
//return some error message using a mediator
//this approach works well inside monoliths where everything happens in the same process
_result.AddResult(cmd.Id, new CommandResult());
return;
}
//using the Aggregate and getting the business state change expressed as an event
var evnt = Transfer.Create(/* args */);
//storing the event
_store.Append(evnt);
//publish event if you want
}
}
from http://blog.sapiensworks.com/post/2016/08/19/DDD-Application-Services-Explained
The problem that you are facing is called Set based validation. There are a lot of articles describing the possible solutions. I will give here an extract from one of them (the context is CQRS but it can be applied to some degree to any DDD architecture):
1. Locking, Transactions and Database Constraints
Locking, transactions and database constraints are tried and tested tools for maintaining data integrity, but they come at a cost. Often the code/system is difficult to scale and can be complex to write and maintain. But they have the advantage of being well understood with plenty of examples to learn from. By implication, this approach is generally done using CRUD based operations. If you want to maintain the use of event sourcing then you can try a hybrid approach.
2. Hybrid Locking Field
You can adopt a locking field approach. Create a registry or lookup table in a standard database with a unique constraint. If you are unable to insert the row then you should abandon the command. Reserve the address before issuing the command. For these sort of operations, it is best to use a data store that isn’t eventually consistent and can guarantee the constraint (uniqueness in this case). Additional complexity is a clear downside of this approach, but less obvious is the problem of knowing when the operation is complete. Read side updates are often carried out in a different thread or process or even machine to the command and there could be many different operations happening.
3. Rely on the Eventually Consistent Read Model
To some this sounds like an oxymoron, however, it is a rather neat idea. Inconsistent things happen in systems all the time. Event sourcing allows you to handle these inconsistencies. Rather than throwing an exception and losing someone’s work all in the name of data consistency. Simply record the event and fix it later.
As an aside, how do you know a consistent database is consistent? It keeps no record of the failed operations users have tried to carry out. If I try to update a row in a table that has been updated since I read from it, then the chances are I’m going to lose that data. This gives the DBA an illusion of data consistency, but try to explain that to the exasperated user!
Accepting these things happen, and allowing the business to recover, can bring real competitive advantage. First, you can make the deliberate assumption these issues won’t occur, allowing you to deliver the system quicker/cheaper. Only if they do occur and only if it is of business value do you add features to compensate for the problem.
4. Re-examine the Domain Model
Let’s take a simplistic example to illustrate how a change in perspective may be all you need to resolve the issue. Essentially we have a problem checking for uniqueness or cardinality across aggregate roots because consistency is only enforced with the aggregate. An example could be a goalkeeper in a football team. A goalkeeper is a player. You can only have 1 goalkeeper per team on the pitch at any one time. A data-driven approach may have an ‘IsGoalKeeper’ flag on the player. If the goalkeeper is sent off and an outfield player goes in the goal, then you would need to remove the goalkeeper flag from the goalkeeper and add it to one of the outfield players. You would need constraints in place to ensure that assistant managers didn’t accidentally assign a different player resulting in 2 goalkeepers. In this scenario, we could model the IsGoalKeeper property on the Team, OutFieldPlayers or Game aggregate. This way, maintaining the cardinality becomes trivial.
You seems to be on the right way, the only stuff I didn't get is what your UserService.register does.
It should take all the values to register a user as input, validate them (using the repository to check the existence of the email) and, if the input is valid store the new User.
Problems can arise when the validation involve complex queries. In that case maybe you need to create a secondary store with special indexes suited for queries that you can't do with your domain model, so you will have to manage two different stores that can be out of sync (a user exists in one but it isn't replicated in the other one, yet).
This kind of problem happens when you store your aggregates in something like a key-value store where you can search just with the id of the aggregate, but if you are using something like a sql database that permits to search using your entities fields, you can do a lot of stuff with simple queries.
The only thing you need to take care is avoid to mix query logic and commands logic, in your example the lookup you need to do is easy, is just one field and the result is a boolean, sometimes it can be harder like time operations, or query spanning multiple tables aggregating results, in these cases it is better to make your (command) service use a (query) service, that offers a simple api to do the calculation like:
interface UserReportingService {
ComplexResult aComplexQuery(AComplexInput input);
}
That you can implement with a class that use your repositories, or an implementation that executes directly the query on your database (sql, or whatever).
The difference is that if you use the repositories you "think" in terms of your domain object, if you write directly the query you think in terms of your db abstractions (tables/sets in case of sql, documents in case of mongo, etc..). One or the other depends on the query you need to do.
It is fine to inject repository into domain.
Repository should have simple inteface, so that domain objects could use it as simple collection or storage. Repositories' main idea is to hide data access under simple and clear interface.
I don't see any problems in calling domain services from usecase. Usecase is suppossed to be archestrator. And domain services are actions. It is fine (and even unavoidable) to trigger domain actions by usecase.
To decide, you should analyze Where is this restriction come from?
Is it business rule? Or maybe user shouldn't be a part of model at all?
Usualy "User" means authorization and authentification i.e behaviour, that for my mind should placed in usecase. I prefare to create separate entity for domain (e.g. buyer) and relate it with usecase's user. So when new user is registered it possible to trigger creation of new buyer.

What is the best way to fill updated data from one aggregate root to another?

I try understand what is the best way for filling property from one Aggregare Root to another.
I have Model Aggregate Root, Category Aggregate Root, Filter Aggregate Root
Every Model can have some Filter list, and can be in one of the Category. Category can have a Filter for inheriting to the Model. When Category property of the Model is updated, Filter must be inherited from Category to the Model, and when Filter property is updated in the Category, all Models from that Category must inherit new value. All inherited Filters can't be updated, but manually added filters can be edited.
One way I "invent" is using Process manager with state which contains Category filter and Models list.
So I will have such behavior:
Category AR UpdateCategoryFilter (command) -> CategoryFilterUpdated (event)
Model AR AddCategory (command) -> CategoryAdded (event), RemoveCategory (command) -> CategoryRemoved (event), InheritFilter (command) -> FilterInherited (event), RemoveInheritedFilter (command) -> InheritedFilterRemoved (event)
Filter AR CreateFilter (command) -> FilterCreated (event)
Process Manager FilterInheritance have correlationIdResolver by categoryId, triggers on [CategoryFilterUpdated, CategoryUpdated] events
PM behavior is like:
current State(filter, models) =>
if CategoryFilterUpdated(... newFilter ...) =>
set new State(... newFilter ...) {
models.forEach(send InheritFilter(model, newFilter))
}
if CategoryAdded(.... modelId ...) =>
set new State(... models.add(modelId) ... ) {
send InheritFilter(modelId, filter)
}
if CategoryRemoved(.... modelId ...) =>
set new State(... models.remove(modelId) ... ) {
send RemoveInheritedFilter(modelId, filter)
}
Is this a right way? Is there some other ways?
Remember, Aggregates are for protecting domain invariants when making state changes, not for simple CRUD. It's not clear what your domain is, and what kind of commands might be sent to a 'Model' where protecting invariants requires knowing what the 'Filters' of the Model are.
You only need to send a command to an Aggregate if the command needs to be validated against the state of the aggregate, or if the command will affect handling of future commands that might be sent to the aggregate. It's not clear whether this is the case for you. Does the Model aggregate have to validate commands/emit events based on the Filters it has? If not, the way to handle this is to do it purely on the read-side - the read side can keep track of the current filter for a Model, and clients/processes can use it as necessary. So, your Model read projection will just need to listen for CategoryAdded, CategoryFilterUpdated, etc. to update the read view of the Model.
If you really do need the Filters to validate Model commands or emit appropriate events in response to those commands, then what you've got seems like an option. But examining your business requirements to see whether filtering could be done outside of the Model aggregate, etc. would be valuable, since copying commands between aggregates increases coupling - you also have a race condition between sending the InheritFilter, etc. commands and the client sending a command to the Model that needs that filter, which seems like a problem that might need client handling to poll for the Model to be ready for the command.
It looks very much like you are doing CRUD style data manipulation operations rather than taking a domain approach.
Another issue you may be having is assuming you can use Aggregate's to display information on the UI. Aggregates don't in principle have any externally visible properties (no getters except the ID). If they did they wouldn't be well encapsulated. You are better off using a read model for use on the UI. This article may give you a better overview of how a typical CQRS application is structured: CQRS + Event Sourcing – A Step by Step Overview
Assuming you are looking to use a DDD style approach I would first have a look at your aggregates. I don't know your domain but from a surface view, it looks like just 1 aggregate root. Not sure what it would be called as I don't know anything about your domain.
I wouldn't expect, for example, real users would say things like "InheritFilter". You may also wish to take a look at this article to help you with how to name your events and by implication, your commands: 6 Code Smells with your CQRS Events – and How to Avoid Them
I hope this helps clear up some of your issues. I personally found getting my head around DDD, CQRS and event sourcing very difficult. I was having to unlearn a bunch of stuff. But I'm a better developer because of it.
Hope this helps.

Communicating between two Bounded Contexts in DDD

I have few different Bounded Contexts in the domain. The validation of a CRUD operation is built in each Bounded Context.
For example, I can create an entity called GAME only if the person creating it is a Group Leader.
I have two Bounded Contexts (BC) in this example. One is the Game BC and the other is the User BC. To solve the problem, in the Game BC, I have to make a domain service call like IsGroupLeader() to the User BC before proceeding on creating the Game.
I don't think this type of communication is recommended by DDD. I can have a User entity also in the Game BC, but I don't want to because the same User entity is being used differently in a different context in a different BC.
My questions are:
Should I use Domain events where the Game BC has to send an event to the User BC asking the status of the User? With this approach, I don't make a synchronous call like IsGroupLeader but an event called is_group_leader. Then the Game BC has to wait for the User BC to process the event and return the status. The Game BC will create the Game entity only after the User BC process the event.
Is CQRS a solution to my problem?
Any idea appreciated.
When integrating BCs, you have a few options. The reason that calling out to an external BC is discouraged is because it requires for both BCs to be operational at the same time. However, this is often quite acceptable and is simpler than the alternative. An alternative is to have the Game BC subscribe to events from the User BC and keep local copies of the data it needs, which in this case is information about whether a user is a group leader. In this way, when the Game BC needs to determine whether a user is a group leader, it doesn't need to call out to the User BC, it just reads locally stored data. The challenge of this event-driven alternative is synchronizing the events. You have the make sure the Game BC receives all appropriate events from the User BC. Another challenge is dealing with eventual consistency, since the BCs may be slightly out of sync at any given point in time.
CQRS is somewhat orthogonal to this problem.
Here is how I would reason about it.
I would argue that the Game BC doesn't know about "Users", it might however know about "Players".
If the Game BC is dependant on an active/current player then it should be passed into the BC when creating the Game BC instance.
eg.
Player currentPlayer = GetPlayerSomehow...();
GameBC gameBC = new GameBC(currentPlayer);
gameBC.DoStuff();
Now your two BC's are still separate, you can test them separately etc.
And to make it all work you simply do something like:
User currentUser = GetCurrentUser();
Player currentPlayer = new Player();
currentPlayer.IsGroupLeader = currentUser.IsGroupLeader;
GameBC gameBC = new GameBC(currentPlayer);
gameBC.DoStuff();
This serves as an anticorruption layer between the UserBC and the GameBC, you can move and validate the state you want from the UserBC into the state you need for your GameBC.
And if your GameBC needs to access many users, you can still pass some sort of mapping service into the game BC that does this kind of transformation internally.
I think you're almost there. Close to a good solution. I'm not so sure you have to split these two into two BC's. Your User Aggregateroot (?) and Game maybe belong in one BC and depend on each other. A User "has a" Membership "to one or many" Games (just guessing your entity relations).
But I'm just brainstorming now. Try to follow :) Different approaches follows:
First
GameBC has a Create() method that actually take a UserMembership as param. Create(UserMembership).
You then through UserMembership entity know what kind of membership and User this. If accepted ,game is created. If not exception is thrown or Game gets a broken rule message, depends on what approach you want to communicate back to client. The coordination can be done in application layer without leakage of domain knowledge.
Second
You do as one of the other answers. You raise a CreateGameEvent within Game.Create(UserId) method. That Event is caught by an EventHandler (registered by IoC in Application startup) that resides in Application layer and look up UserMembership through repository. The small leakage of domain knowledge is that business rule that knows who are allowed yo do what are verified in application layer. This can be solved by letting the CreateGameEventHandler take UserId and RuleRef (can be string "CAN_CREATE_GAME" or enum) and letting a UserPermission object verify the permission. If not. Exception is thrown and catched in application layer.
Drawback can be that you do mot want permission reference strings be hardcoded in Create method.
Third
...continues where second approach ends. You know that GameBC may not be the right place to do user permission lookups if you follow SRP principle. But the action is triggered around that method somehow. An alternative an be a Create(GroupLeader user). OR you can have Game.Create(User user) then do a validation that User is GroupLeader type. Create(GroupLeader) tells you what you need to call this method.
Last
Maybe an alternative that I like more now when writing this. When you want to create an entity I usually let that Create(Save) method be on the repository. The IGameRepository interface is located next to Game Entity in domain assembly project. But You can also create a GameFactory that are responsible for starting the lifecycle of Game Entity. Here is also a good place to put Create method... GameFactory.Create(GroupLeader) { return new Game.OwnerUserId = GroupLeader.Id; }
Then you just save it IGameRepository.Save(Game)
Then you have an intuitive and self describing way of telling other developers that "You must have a GroupLeader instance to create a Game".
Finally I hope you realize that you know the domain and you will figure out what suits you best. Be pragmatic and don't go Eric Evan hardcore. There is so many devs out there that are stuck in a "religion" in how things are gonna be done. Size of project, money, time, and dependencies to other systems etc. also affect how well you can be strict in doing DDD.
Good luck.
To cope with the kind of problems you are facing, we use bounded roles a modeling pattern that emerged over the years and proved to work very well. Bounded contexts are defined after semantical units that often, in enterprise organizations, can be mapped to specific roles.
That should be obvious considering that different roles face different problems and thus speak slightly (or entirely) different languages.
Thus, we always model the roles that interact with our application as a junction point between applicative requirements (infrastructure, persistence, UI, localization etc...) and business rules (the domain) and we code them in different modules (aka assemblies or packages).
As for your second question, CQRS can be a way to code the kind of interactions between BCs that you are describing, but I don't like it in this particular context.
I think I may have to follow a different approach where I will make the User entity part of the Game BC (the same entity is part of User BC also). I will use the Repository to read the IsGroupLeader flag from the db in the Game BC. This way, the dependency on the User BC is removed and no communication is needed with the User BC.
What do you think?
I would suggest to pass the role of user and user information to Game bounded context service and also have a GroupLeader value object inside Game BC. this way you can always know who is group_leader.

Please clarify how create/update happens against child entities of an aggregate root

After much reading and thinking as I begin to get my head wrapped around DDD, I am a bit confused about the best practices for dealing with complex hierarchies under an aggregate root. I think this is a FAQ but after reading countless examples and discussions, no one is quite talking about the issue I'm seeing.
If I am aligned with the DDD thinking, entities below the aggregate root should be immutable. This is the crux of my trouble, so if that isn't correct, that is why I'm lost.
Here is a fabricated example...hope it holds enough water to discuss.
Consider an automobile insurance policy (I'm not in insurance, but this matches the language I hear when on the phone w/ my insurance company).
Policy is clearly an entity. Within the policy, let's say we have Auto. Auto, for the sake of this example, only exists within a policy (maybe you could transfer an Auto to another policy, so this is potential for an aggregate as well, which changes Policy...but assume it simpler than that for now). Since an Auto cannot exist without a Policy, I think it should be an Entity but not a root. So Policy in this case is an aggregate root.
Now, to create a Policy, let's assume it has to have at least one auto. This is where I get frustrated. Assume Auto is fairly complex, including many fields and maybe a child for where it is garaged (a Location). If I understand correctly, a "create Policy" constructor/factory would have to take as input an Auto or be restricted via a builder to not be created without this Auto. And the Auto's creation, since it is an entity, can't be done beforehand (because it is immutable? maybe this is just an incorrect interpretation). So you don't get to say new Auto and then setX, setY, add(Z).
If Auto is more than somewhat trivial, you end up having to build a huge hierarchy of builders and such to try to manage creating an Auto within the context of the Policy.
One more twist to this is later, after the Policy is created and one wishes to add another Auto...or update an existing Auto. Clearly, the Policy controls this...fine...but Policy.addAuto() won't quite fly because one can't just pass in a new Auto (right!?). Examples say things like Policy.addAuto(VIN, make, model, etc.) but are all so simple that that looks reasonable. But if this factory method approach falls apart with too many parameters (the entire Auto interface, conceivably) I need a solution.
From that point in my thinking, I'm realizing that having a transient reference to an entity is OK. So, maybe it is fine to have a entity created outside of its parent within the aggregate in a transient environment, so maybe it is OK to say something like:
auto = AutoFactory.createAuto();
auto.setX
auto.setY
or if sticking to immutability, AutoBuilder.new().setX().setY().build()
and then have it get sorted out when you say Policy.addAuto(auto)
This insurance example gets more interesting if you add Events, such as an Accident with its PolicyReports or RepairEstimates...some value objects but most entities that are all really meaningless outside the policy...at least for my simple example.
The lifecycle of Policy with its growing hierarchy over time seems the fundamental picture I must draw before really starting to dig in...and it is more the factory concept or how the child entities get built/attached to an aggregate root that I haven't seen a solid example of.
I think I'm close. Hope this is clear and not just a repeat FAQ that has answers all over the place.
Aggregate Roots exist for the purpose of transactional consistency.
Technically, all you have are Value Objects and Entities.
The difference between the two is immutability and identity.
A Value Object should be immutable and it's identity is the sum of it's data.
Money // A value object
{
string Currency;
long Value;
}
Two Money objects are equal if they have equal Currency and equal Value. Therefore, you could swap one for the other and conceptually, it would be as if you had the same Money.
An Entity is an object with mutability over time, but whose identity is immutable throughout it's lifetime.
Person // An entity
{
PersonId Id; // An immutable Value Object storing the Person's unique identity
string Name;
string Email;
int Age;
}
So when and why do you have Aggregate Roots?
Aggregate Roots are specialized Entities whose job is to group a set of domain concepts under one transactional scope for purpose of data change only. That is, say a Person has Legs. You would need to ask yourself, should changes on Legs and changes on Person be grouped together under a single transaction? Or can I change one separately from the other?
Person // An entity
{
PersonId Id;
string Name;
string Ethnicity;
int Age;
Pair<Leg> Legs;
}
Leg // An entity
{
LegId Id;
string Color;
HairAmount HairAmount; // none, low, medium, high, chewbacca
int Length;
int Strength;
}
If Leg can be changed by itself, and Person can be changed by itself, then they both are Aggregate Roots. If Leg can not be changed alone, and Person must always be involved in the transaction, than Leg should be composed inside the Person entity. At which point, you would have to go through Person to change Leg.
This decision will depend on the domain you are modeling:
Maybe the Person is the sole authority on his legs, they grow longer and stronger based on his age, the color changes according to his ethnicity, etc. These are invariants, and Person will be responsible for making sure they are maintained. If someone else wants to change this Person's legs, say you want to shave his legs, you'd have to ask him to either shaves them himself, or hand them to you temporarily for you to shave.
Or you might be in the domain of archeology. Here you find Legs, and you can manipulate the Legs independently. At some point, you might find a complete body and guess who this person was historically, now you have a Person, but the Person has no say in what you'll do with the Legs you found, even if it was shown to be his Legs. The color of the Leg changes based on how much restoration you've applied to it, or other things. These invariants would be maintained by another Entity, this time it won't be Person, but maybe Archaeologist instead.
TO ANSWER YOUR QUESTION:
I keep hearing you talk about Auto, so that's obviously an important concept of your domain. Is it an entity or a value object? Does it matter if the Auto is the one with serial #XYZ, or are you only interested in brand, colour, year, model, make, etc.? Say you care about the exact identity of the Auto and not just it's features, than it would need to be an Entity of your domain. Now, you talk about Policy, a policy dictates what is covered and not covered on an Auto, this depends on the Auto itself, and probably the Customer too, since based on his driving history, the type and year and what not of Auto he has, his Policy might be different.
So I can already conceive having:
Auto : Entity, IAggregateRoot
{
AutoId Id;
string Serial;
int Year
colour Colour;
string Model
bool IsAtGarage
Garage Garage;
}
Customer : Entity, IAggregateRoot
{
CustomerId Id;
string Name;
DateTime DateOfBirth;
}
Policy : Entity, IAggregateRoot
{
string Id;
CustomerId customer;
AutoId[] autos;
}
Garage : IValueObject
{
string Name;
string Address;
string PhoneNumber;
}
Now the way you make it sound, you can change a Policy without having to change an Auto and a Customer together. You say things like, what if the Auto is at the garage, or we transfer an Auto from one Policy to another. This makes me feel like Auto is it's own Aggregate Root, and so is Policy and so is Customer. Why is that? Because it sounds like it is the usage of your domain that you would change an Auto's garage without caring that the Policy be changed with it. That is, if someone changes an Auto's Garage and IsAtGarage state, you don't care not to change the Policy. I'm not sure if I'm being clear, you wouldn't want to change the Customer's Name and DateOfBirth in a non transactional way, because maybe you change his name, but it fails to change the Date and now you have a corrupt customer whose Date of Birth doesn't match his name. On the other hand, it's fine to change the Auto without changing the Policy. Because of this, Auto should not be in the aggregate of Policy. Effectively, Auto is not a part of Policy, but only something that the Policy keeps track of and might use.
Now we see that it then totally make sense that you are able to create an Auto on it's own, as it is an Aggregate Root. Similarly, you can create Customers by themselves. And when you create a Policy, you simply must link it to a corresponding Customer and his Autos.
aCustomer = Customer.Make(...);
anAuto = Auto.Make(...);
anotherAuto = Auto.Make(...);
aPolicy = Policy.Make(aCustomer, { anAuto, anotherAuto }, ...);
Now, in my example, Garage isn't an Aggregate Root. This is because, it doesn't seem to be something that the domain directly works with. It is always used through an Auto. This makes sense, Insurance companies don't own garages, they don't work in the business of garages. You wouldn't ever need to create a Garage that existed on it's own. It's easy then to have an anAuto.SentToGarage(name, address, phoneNumber) method on Auto which creates a Garage and assign it to the Auto. You wouldn't delete a Garage on it's own. You would do anAuto.LeftGarage() instead.
entities below the aggregate root should be immutable.
No. Value objects are supposed to be immutable. Entities can change their state.
Just need to make sure You do proper encapsulation:
entities modifies themselves
entities are modified through aggregate root only
but Policy.addAuto() won't quite fly because one can't just pass in a new Auto (right!?)
Usually it's supposed to be so. Problem is that auto creation task might become way too large. If You are lucky and, knowing that entities can be modified, are able to divide smoothly it into smaller tasks like SpecifyEngine, problem is resolved.
However, "real world" does not work that way and I feel Your pain.
I got case when user uploads 18 excel sheets long crap load of data (with additional fancy rule - it should be "imported" whatever how invalid data are (as I say - that's like saying true==false)). This upload process is considered as one atomic operation.
What I do in this case...
First of all - I have excel document object model, mappings (e.g. Customer.Name==1st sheet, "C24") and readers that fill DOM. Those things live in infrastructure far far away.
Next thing - entity and value objects in my domain that looks similar to DOM dto`s, but only projection that I'm interested in, with proper data types and according validation. + I Have 1:1 association in my domain model that isolates dirty mess out (luckily enough, it kind a fits with ubiquitous language).
Armed with that - there's still one tricky part left - mapping between excel DOM dtos to domain objects. This is where I sacrifice encapsulation - I construct entity with its value objects from outside. My thought process is kind a simple - this overexposed entity can't be persisted anyway and validness still can be forced (through constructors). It lives underneath aggregate root.
Basically - this is the part where You can't runaway from CRUDyness.
Sometimes application is just editing bunch of data.
P.s. I'm not sure that I'm doing right thing. It's likely I've missed something important on this issue. Hopefully there will be some insight from other answerers.
Part of my answer seems to be captured in these posts:
Domain Driven Design - Parent child relation pattern - Specification pattern
Best practice for Handling NHibernate parent-child collections
how should i add an object into a collection maintained by aggregate root
To summarize:
It is OK to create an entity outside its aggregate if it can manage its own consistency (you may still use a factory for it). So having a transient reference to Auto is OK and then a new Policy(Auto) is how to get it into the aggregate. This would mean building up "temporary" graphs to get the details spread out a bit (not all piled into one factory method or constructor).
I'm seeing my alternatives as either:
(a) Build a DTO or other anemic graph first and then pass it to a factory to get the aggregate built.
Something like:
autoDto = new AutoDto();
autoDto.setVin(..);
autoDto.setEtc...
autoDto.setGaragedLocation(new Location(..));
autoDto.addDriver(...);
Policy policy = PolicyFactory.getInstance().createPolicy(x, y, autoDto);
auto1Dto...
policy.addAuto(auto1Dto);
(b) Use builders (potentially compound):
builder = PolicyBuilder.newInstance();
builder = builder.setX(..).setY(..);
builder = builder.addAuto(vin, new Driver()).setGaragedLocation(new Location());
Policy = builder.build();
// and how would update work if have to protect the creation of Auto instances?
auto1 = AutoBuilder.newInstance(policy, vin, new Driver()).build();
policy.addAuto(auto1);
As this thing twists around and around a couple things seem clear.
In the spirit of ubiquitous language, it makes sense to be able to say:
policy.addAuto
and
policy.updateAuto
The arguments to these and how the aggregate and the entity creation semantics are managed is not quite clear, but having to look at a factory to understand the domain seems a bit forced.
Even if Policy is an aggregate and manages how things are put together beneath it, the rules about how an Auto looks seem to belong to Auto or its factory (with some exceptions for where Policy is involved).
Since Policy is invalid without a minimally constructed set of children, those children need to be created prior or within its creation.
And that last statement is the crux. It looks like for the most part these posts handle the creation of children as separate affairs and then glue them. The pure DDD approach would seem to argue that Policy has to create Autos but the details of that spin wildly out of control in non-trivial cases.

Resources