In my domain I might have a entity called User that represents a person and Tenant, an entity that represents a business.
One might think that this is a administrative user, and as such, it should be able to register new users, which in terms of code would be translated to basically 3 forms:
-adminUserInstance.CreateUser(newUserDTO);
-tenantInstance.CreateUser(newUserDTO)
-newUserInstace.SelfSave()
Being newUserInstace.SelfSave() a necessity because of self-registration, does the other two make sense? Should i keep only the self registration and turn to a model of affiliation, where the same user can be part of multiple tenants?
In broader terms: should Questions/Answers be created by Users or self created and then tied to a given User? and on even broader terms: Should entities hold the knowledge to create other (not any-others) entities or the entities should be able to create themselves and have the "requester", for example, call a domain service that will bundle them up?
In broader terms: should Questions/Answers be created by Users or self created and then tied to a given User? and on even broader terms: Should entities hold the knowledge to create other (not any-others) entities or the entities should be able to create themselves and have the "requester", for example, call a domain service that will bundle them up?
Udi Dahan's technical guidance was that you should always get an entity, and use it to create the new entity. "Customers don’t just appear out of thin air."
That said, creating aggregate root entities is weird; not "wrong", but it deviates from the usual patterns of dispatching commands to the aggregate you are going to modify.
Entities can be created by entities but only inside the same aggregate. So, if an aggregate creates an entity then that entity is a nested entity; it cannot be referenced outside the aggregate's boundary. You put the creation of nested entities inside the aggregate because the aggregate needs to enforce some invariants and this is a decision to make when you design your Aggregates.
On the other hand, aggregate roots (AR) are created by the client code (an Application service in most cases) but the AR enforces it's own invariants! So, in PHP code this should look like this:
//somewhere in an Application service
function createUser($id, $username, $password)
{
$user = new User(); //an AR should always be new-able, i.e. with not injected dependencies
$user->registerNew($id, $username, $password); //here the invariants are enforced
$this->userRepository->addOrSave($user);
}
newUserInstace.SelfSave()
An aggregate does not "save" (persists) itself. That is the job of an Application service. Anyway, "save" does not seem to be from your ubiquitous language, you need a more proper name ("register"?).
Related
I have some Entities and I am trying to follow Domain Driven Design practices to identify Aggregates. I somehow cant do this because I either break the rule of Entities not being allowed to reference non-root Entities of other Aggregates, or I cant form Aggregates at all.
I have the following Entities: Organisation, JobOffer, Candidate, and JobApplication.
An Organisation creates JobOffers but may only have a limited amount of active JobOffers.
A Candidate creates JobApplications but may only have a limited amount of active JobApplications.
A JobApplication references a JobOffer that it is meant for.
Based on that I have to know how many JobOffers an Organisation has before I can create a new one (enforcing limits), I assume Organisation should be an Root-Entity that owns JobOffers. The same applies to Candidates and JobApplications. Now I have two Aggregates: Organisation with JobOffers and Candidate with JobApplications. But... I need to reference JobOffer from JobApplication... and that breaks the rule that I cant reference non-Root-Entities.
I have looked for and found similar questions on this forum but I somehow still cant figure it out, so sorry in advance - I appreciate any help.
I general, you should avoid holding object references to other aggregates but rather reference other aggregates by id. In some cases it can be valid to reference some entity within in another aggregate, but again this should be done via id as well.
If you go this way you should reference a composite id. Aggregates are meant to depict logical boundaries and also transactional boundaries. Child entity ids which are modelled as part of the aggregate only need to be unique inside the boundaries of that aggregate. This makes it a lot easier to focus on stuff just inside those boundaries when performing actions in your system. Even if you are using UUIDs (or GUIDs), if you really need to reference a child entity of another aggregate - let's say you have good reasons for that - you should model the id graph via the aggregate root which means always knowing the id of the other aggregate in combination with the id of the entity you are interested in. That means referencing a composite id.
But: whenever I think I need to reference a child entity of another aggregate root at first I investigate this more deeply. This would mean that this child entity might be important as a stand-alone entity as well.
Did I miss to discover another aggregate root?
In your case, looking at your domain model diagram, I suspect JobOffer should be an aggregate on its own. Of course I don't know your domain but I can at least guess that there might be some transactions performed in your system allowing to mutate job offers on its own without requiring to consider organization specific business invariants. If this is the case, you should rethink the domain model and consider making JobOffer an aggregate root on its own. In this case your initial problem get's resolved automatically. Also note that modelling job offers as aggregates can make actions performed on organizations simpler as well as you do not need to load all the job offers for that organization when loading the organization aggregate. This might of course not be relevant in your case and really depends on the maximum amount of job offers for an organization.
So I think, depending on your business requirements and domain logic invariants I would recommd one of the folllwing two options:
Reference the foreign child entity only through a composite id including the id of other the aggregate + the child entity id (e.g. by creating some value object that represents this reference as a strong type)
Make JobOffer an aggregate on its own if the mentioned considerations hold true in your case
We are building a system which can sell our api services to multiple companies.
We have
companies (companies which purchased our api)
accounts (each company can have multiple accounts, and each account has it's user types)
users (users within account)
Infrastructurally, it looks something like this:
"company1" : {
"accounts" : [
account1 :{"users" : [{user1,user2}], accountType},
account2 :{"users" : [{user1,user2}], accountType},
]}
One of the business rules states that users can't change accounts after registration.
Other rule states that user can change his type, but only within that account type.
From my understanding, my domain model should be called UserAccount, and it should consist of Account, User and UserType entities, where Account would be aggregate root.
class UserAccount{
int AccountId;
string AccountName;
int AccountTypeId;
List<UserTypes> AvailableUserTypesForThisAccount
User User
void SetUserType(userTypeId){
if(AvailableUserTypesForThisAccount.Contains(userTypeId) == false)
throw new NotSupportedException();
}
}
With this aggregate, we can change type of the user, but it can only be type which is available for that account (one of invariants).
When I fetch UserAccount from repository, I would fetch all necessary tables (or entity data objects) and mapped them to aggregate, and returned it as a whole.
Is my understanding and modeling going in to the right direction?
It's important to understand the design trade-off of aggregates; because aggregates partition your domain model into independent spaces, you gain the ability to modify unrelated parts of the model concurrently. But you lose the ability to enforce business rules that span multiple aggregates at the point of change.
What this means is that you need to have a clear understanding of the business value of those two things. For entities that aren't going to change very often, your business may prefer strict enforcement over concurrent changes; where the data is subject to frequent change, you will probably end up preferring more isolation.
In practice, isolation means evaluating whether or not the business can afford to mitigate the cases where "conflicting" edits leave the model in an unsatisfactory state.
With this aggregate, we can change type of the user, but it can only be type which is available for that account (one of invariants).
With an invariant like this, an important question to ask is "what is the business cost of a failure here"?
If User and Account are separate aggregates, then you face the problem that a user is being assigned to a "type" at the same time that an account is dropping support for that type. So what would it cost you to detect (after the change) that a violation of the "invariant" had occurred, and what would it cost to apply a correction?
If Account is relatively stable (as seems likely), then most of those errors can be mitigated by comparing the user type to a cached list of those allowed in the account. This cache can be evaluated when the user is being changed, or in the UI that supports the edit. That will reduce (but not eliminate) the error rate without compromising concurrent edits.
From my understanding, my domain model should be called UserAccount, and it should consist of Account, User and UserType entities, where Account would be aggregate root.
I think you've lost the plot here. The "domain model" isn't really a named thing, it's just a collection of aggregates.
If you wanted an Account aggregates that contain Users and UserTypes, then you would probably model it something like
Account : Aggregate {
accountId : Id<Account>,
name : AccountName,
users : List<User>,
usertypes : List<UserType>
}
This design implies that all changes to a User need to be accessed via the Account aggregate, and that no User belongs to more than one account, and that no other aggregate can directly reference a user (you need to negotiate directly with the Account aggregate).
Account::SetUserType(UserHint hint, UserType userTypeId){
if(! usertypes.Contains(userTypeId)) {
throw new AccountInvariantViolationException();
}
User u = findUser(users, hint);
...
}
When I fetch UserAccount from repository, I would fetch all necessary tables (or entity data objects) and mapped them to aggregate, and returned it as a whole.
Yes, that's exactly right -- it's another reason that we generally prefer small aggregates loosely coupled, rather than one large aggregate.
what about having only the relationship between Account and User live in the Account aggregate as well as the type of user (as an AccountUser entity) and have the rest of the user information live in a separate User aggregate?
That model could work for some kinds of problems -- in that case, the Account aggregate would probably looks something like
Account : Aggregate {
accountId : Id<Account>,
name : AccountName,
users : Map<Id<User>,UserType>
usertypes : List<UserType>
}
This design allows you to throw exceptions if somebody tries to remove a UserType from an Account when some User is currently of that type. But it cannot, for example, ensure that the user type described here is actually consistent with the state of the independent User aggregate -- or event be certain that the identified User exists (you'll be relying on detection and mitigation for those cases).
Is that better? worse? It's not really possible to say without a more thorough understanding of the actual problem being addressed (trying to understand ddd from toy problems is really hard).
The principle is to understand which the business invariant that must be maintained at all times (as opposed to those where later reconciliation is acceptable), and then group together all of the state which must be kept consistent to satisfy the invariant.
But what if account can have hundreds or thousands of users? What would be your vision of aggregate?
Assuming the same constraints: that we have some aggregate that is responsible for the allowed range of user types.... if the aggregate got to be too large to manage in a reasonable way, and the constraints imposed by the business cannot be relaxed, then I would probably compromise the "repository" abstraction, and allow the enforcement of the set validation rules to leak into the database itself.
The conceit of DDD, taken from its original OO best practices roots, is that the model is real, and the persistence store is just an environmental detail. But looked at with a practical eye, in a world where the processes have life cycles and there are competing consumers and... it's the persistence store that represents the truth of the business.
I'm trying to follow DDD principles to create a model for determining whether or not an Identity has access to an Action belonging to a Resource.
A Resource (e.g. a webservice) is something that holds a number of Actions (e.g. methods), which can be accessed or not. An Identity is something that wants to access one or more Actions on a Resource. For example, someone uses an api-key in a call to a webservice method, and it must be determined whether or not access is allowed.
As I currently see it, Identity and Resource are aggregate roots, and Action is an entity belonging to Resource. It doesn't seem to make sense for an Action to live on its own; it will always belong to one Resource. An Identity needs to know to which Resource Actions it has access. This seems to suggest the following model.
However, as I understand it, this violates the principle that something outside an aggregate cannot reference an entity within the aggregate. It must go through the root. Then I'm thinking, what if Action was the aggregate root and Resource an entity? But that doesn't seem very logical to me. I've also been thinking of merging Resource and Action into one entity, which would then be an aggregate root, but that also seems wrong to me.
So it leaves me kind of stuck on how to model this correctly using DDD principles. Anyone have a good idea on how to model this?
Update: The model I'm trying to create is the identity model for defining which resource actions an Identity is allowed to access. It is not a model for the actual implementation of resources and actions.
Update 2 - invariants:
Id of all objects is given at birth, is unique, and doesn't change. ApiKey of Identity must be unique across all Identities.
Name of Action must be unique within aggregate, but two different Resources can have Actions with same names, e.g. Resource "R1" can have an Action "A1" and Resource "R2" can also have an Action "A1", but the two "A1"s are not the same.
Query or Write Operation?
The domain model in terms of aggregates and entities has it's purpose in DDD in order to simplify expression and enforcement of the invariants - as write operations are applied to the model.
As mentioned in #VoiceOfUnreason's answer, the question 'Can this user do action A on resource R' is a question that doesn't necessarily need to flow through the domain model - it can be answered with a query against either a pre-projected read-only model, or standard SQL querying against the tables that make up the write model persistence (depend on your needs).
Splitting Contexts to Simplify Invariants
However, your question, whilst mostly about how to identify if an identity is allowed to carry out an action, is implicitly seeking a simpler model for the updating of resources, actions and permissions. So to explore that idea... there are implicitly two types of write operations:
Defining available resources and actions
Defining which resource action combinations a particular identity is permitted to carry out
It's possible that the model for these two types of operations might by simplified if they were split into different bounded contexts.
In the first, you'd model as you have done, an Aggregate with Resource as the aggregate root and Action as a contained entity. This permits enforcing the invariant that the action name must be unique within a resource.
As changes are made in this context, you publish events e.g. ActionAddedToResource, ActionRemovedFromResource.
In the second context, you'd have three aggregates:
Identity
ResourceAction
Properties: Id, ResourceId, ResourceName, ActionId, ActionName
Permission
ResourceAction instances would be updated based events published from the first context - created on ActionAddedToResource, removed on ActionRemovedFromResource. If there is a resource with no actions, there is no ResourceAction at all.
Permission would contain two identity references - IdentityId and ResourceActionId
This way when carrying out the operation "Permit this user to do this action on this resource" the operation is just to create a new Permission instance - reducing the set of operations that affect the Identity aggregate's consistency boundary - assuming there are no invariants that require the concept of a 'permission' to be enforced within an Identity aggregate?
This also simplifies the query side of things, as you just need to search for a Permission entry with matching identityId, resourceName and actionName after joining Permissions to ResourceActions.
Responsibility Layers
The DDD Book in the section on Strategic Design refers to organising your contexts according to responsibility layers. To use the terms from the book, the above suggestion is based on the idea of a 'capability' responsibility layer (defining resources and actions) and an 'operational' responsibility layer (defining identity permissions and checking identity permissions).
For example, someone uses an api-key in a call to a webservice method, and it must be determined whether or not access is allowed.
That's a query. Fundamentally, there's nothing wrong with answering a query by joining two read-only copies of entities that belong to different aggregates.
You do need to be aware that, because the aggregates can change independently of each other, and because they can change independently of your query, the answer you get when you do the join may be stale, and not entirely consistent.
For example, you may be joining a copy of an Identity written 100ms ago to a copy of an Action written 200ms ago. Either of the aggregates could be changing while you are running the query.
Based on the invariants you mention, Identity can contain a Resources dictionary/map where resourceId is the key and the value is a set of unique action names/ids. This gives you uniqueness of action names for each resource per identity:
Map<Resource, Set<Action>>
Alternatively, you could have a set/list of Resources and they have a collection of Actions on them. Uniqueness can be enforced by the collection types available in the language you're coding in:
Set<Resource> Resources
class Resource {
Set<Action> Actions
}
Even simpler, just create a Resource-Action key by combining the two ids and store it in a set or something to give you uniqueness:
Resource1-Action1
Resource1-Action2
Resource2-Action1
...etc
You can then have a method on Identity to add a new Resource-Action combination.
I don't see anything in your description to warrant Actions being Entities as they appear to have no identity of their own.
This is really simple though, so I am presuming you've simplified the domain considerably.
I will also expand on the bit identified by #VoiceOfUnreason:
For example, someone uses an api-key in a call to a webservice method,
and it must be determined whether or not access is allowed.
How would the particular bit of exposed functionality know what security is applied to it? The answer is provided by #Chris Simon: Permission.
I have a common implementation that I use that has not been distilled into an Identity & Access BC of its own but follows closely with what you are attempting --- I hope :)
A Session has a list of Permission strings. Typically I use a uri to represent a permission since it is quite readable. Something like my-system:\\users\list. Anyway, how the user is assigned these permissions could be anything. There may very well be a Role containing permissions and a user is assigned to one or more roles; or the user may even have a custom list of permissions.
When a SessionToken is requested (via authentication) the server retrieves the permissions for the relevant user and creates a session with the relevant permissions assigned to it. This results in a read-side token/permission.
Each exposed bit of functionality (such as a rest endpoint) is assigned a permission. In c# web-api it is simply an attribute on the method:
[RequiredPermission("my-system:\\order\create")]
My session token is passed in the header and a quick check determines whether the session has expired and whether the session (assigned to the user) has access to the resource.
Using your design the Action may very well carry the required Permission. The User would still require a list of either roles or UserAction entries that contain, perhaps, the ResourceId and ActionId. When the use logs in the read-optimized session structures are created using that structure.
If there is an arbitrary Action list that can be assigned to any Resource then both Resource and Action are probably aggregates. Then you would need a ResourceAction as mentioned by #Chris Simon. The ResourceAction would then contain the Permission.
That's my take on it...
We are trying to model an RBAC-based user maintenance system using DDD principles. We have identified the following entities:
Authorization is an Aggregate Root with the following:
User (an entity object)
List<Authority> (list of value objects)
Authority contains the following value objects:
AuthorityType (base class of classes Role and Permission)
effectiveDate
Role contains a List<Permission>
Permission has code and description attributes
In a typical scenario, Authorization is definitely the Aggregate Root since everything in user maintenance revolves around that (e.g. I can grant a user one or more Authority-ies which is either a Role or Permission)
My question is : what about Role and Permission? Are they also Aggregate Roots in their own separate contexts? (i.e. I have three contexts, authorization, role, permission). While can combine all in just one context, wouldn't the Role be too heavy enough since it will be loaded as part of the Authorization "object graph"?
Firstly I can't help but feel you've misunderstood the concept of a bounded context. What you've described as BC's I would describe as entities. In my mind, bounded contexts serve to give entities defined in the ubiquitous language a different purpose for a given context.
For example, in a hospital domain, a Patient being treated in the outpatients department might have a list of Referrals, and methods such as BookAppointment(). A Patient being treated as an Inpatient however, will have a Ward property and methods such as TransferToTheatre(). Given this, there are two bounded contexts that patients exist in: Outpatients & Inpatients. In the insurance domain, the sales team put together a Policy that has a degree of risk associated to it and therefore cost. But if it reaches the claims department, that information is meaningless to them. They only need to verify whether the policy is valid for the claim. So there is two contexts here: Sales & Claims
Secondly, are you just using RBAC as an example while you experiment with implementing DDD? The reason I ask is because DDD is designed to help solve complex business problems - i.e. where calculations are required (such as the risk of a policy). In my mind RBAC is a fairly simple infrastructure service that doesn't concern itself with actual domain logic and therefore doesn't warrant a strict DDD implementation. DDD is expensive to invest in, and you shouldn't adopt it just for the sake of it; this is why bounded contexts are important - only model the context with DDD if it's justifiable.
Anyway, at the risk of this answer sounding to 'academic' I'll now try to answer your question assuming you still want to model this as DDD:
To me, this would all fit under one context (called 'Security' or something)
As a general rule of thumb, make everything an aggregate that requires an independent transaction, so:
On the assumption that the system allows for Authorities to be added to the Authorization object, make Authorization an aggregate. (Although there might be an argument for ditching Authorization and simply making User the aggregate root with a list of Authorities)
Authorities serve no meaning outside of the Authorization aggregate and are only created when adding one, so these remain as entities.
On the assumption that system allows for Permissions to be added to a Role, Role becomes an aggregate root.
On the assumption that Permissions cannot be created/delete - i.e. they are defined by the system itself, so these are simple value objects.
Whilst on the subject of aggregate design, I cannot recommend these articles enough.
I have two Entities Publisher and SocialAccount , both are independent and having relationship of Many to Many. Both are root Aggregates , now i cannot get social account through Publisher and I want to convert M To M relationship to 1 To M. So I Introduced another entity Registration , will have {PubID, SocID, CreateDate}. Now there is 1 To M relationship between Publisher and Registration and 1 to 1 between Registration and SocialAccount. so publisher will have
List <Registrations> _Registrations {get;set;}
But when I create aggregate boundaries, Publisher is my root and according to aggregate principle, only root aggregate will hold reference to another root aggregate. But here Registration hold reference.
So do i am violating aggregate principle , because registration is connected Social Account entity.
Your use of aggregate concept appears to be incorrect. Objects within an aggregate can in fact hold references to other aggregates. The rule is an external object cannot hold a reference to something within an aggregate.
On the Registration object, you seem to have created it to avoid some aggregate to aggregate relationships. That is not why you create an object. If there is in fact a Registration in your domain, create it and model it. If it is not in your domain, don't add it just to traverse some path.
Having added Registration, you say it cannot hold a reference to Social Account because it is part of Publisher. That is not the rule, but more important how did Registration suddenly become part of the Publisher aggregate anyway? By virtue only of Publisher having a Registration collection?
An aggregate is a group of objects that are treated as one unit for maintaining state and invariants. Existence of a relationship by itself does not confer membership in an aggregate.
But look at the other side now. Registration is 1 to 1 with Social Account. And if we remove a Social Account does it ever make sense to still have a Registration with a Publisher? If not then Registration probably is in fact part of the SocialAccount aggregate instead. That is why we create aggregates - to ensure objects and their relationships are always valid after a state change. If the change of state of removing a SocialAccount includes removing all Registrations associated with that account, we would want to include it in the aggregate to enforce that rule.
Now you have indeed violated the "aggregate rule" - you have an external relationship from Publisher to an object, Registration, that is an internal part of the SocialAccount aggregate.
These concepts are more than just rules, they have reasons. You need to review what aggregate really means, understand what the rules actually say and what they really mean, why they exist in the first place. Then reevaluate your relationships and aggregate definitions accordingly.
First we need an abstraction for encapsulating references within the model.
An AGGREGATE is a cluster of associated objects that we treat as a unit for the purpose of data changes.
Each AGGREGATE has a root and a boundary. The boundary defines what is inside the AGGREGATE. The root is a single, specific ENTITY contained in the AGGREGATE. The root is the only member of the AGGREGATE that outside objects are allowed to hold references to, although objects within the boundary may hold references to each other. ENTITIES other than the root have local identity, but that identity needs to be distinguishable only within the AGGREGATE, because no outside object can ever see it out of the context of the root ENTITY.
what you think about it Ssyphus?