Guidelines to decide when a domain role needs to be explicitly modelled - domain-driven-design

I looking for some guidelines as to when one must explicitly model a role in the domain model.
I will explain my current stance with the help of an example here.
Say we are building a health care system, and the business requirement states
"That only doctors with 3+ years of experience and certain
qualifications can perform surgeries"
In this case it is evident that the act of doing a surgery can only be performed by a person playing the role of a doctor and the doctor needs to meet certain prerequisites to perform the action
docter.performSurgery()
So basically all doctors are not the same
This method will probably check if the preconditions are met
So in the above cases, I will model the role explicitly.
Now lets consider the alternate scenario.
Only a admin can approve of a funds transfer
In the above case I do not find any need to model this role in domain, as their are no rules distinguishing one admin from another in my domain.
Any person/userlogin with the permission of admin can perform this action, I would rather design this into my security infrastructure and ensure that the
approveTransfer() method invoked on the application layer is invoked only if the currently logged in user has the ADMIN permission.
So the "domain model" by which i mean classes like the Account class is unaware of this rule, this is codified in the application layer either via AOP or probably the AccountService class or the like.
What do the wise men have to say about this ? :)

When designing aggregates I always ask myself an important question.
What is the consistency boundary for the process I'm attempting to model?
I ask what rules must be applied during any one atomic operation. This is referred to as a transactional boundary, and its your bread butter when defining your invariants (rules that must always be true during the lifetime of an atomic operation - start to end).
As I see it, the rule that a doctor/surgeon must have n years of experience - for a particular operation - is an invariant that must always be transactionally consistent (such as when performing a surgery). Therefor it should be modeled as a transactional boundary within a single aggregate.
Because aggregates can only guarantee the consistency within themselves, the invariants it is responsible for should not be leaked outside of it. In my opinion, and assuming that doctor is an aggregate, a separate roles model should not be responsible for an invariant that the doctor's model itself should be responsible for.
Aggregate to aggregate relationships should really only be established to provide 'help' in giving some missing piece of information. But the rules and how that information is interpreted should be isolated within its respective aggregate.
A separate situation can arise for user authentication. You may have a bounded context with a Customer model, but the details of permissions, authentication, and roles are so vast as to require an entirely separate system to deal with. In this case you may end up creating a separate bounded context for User Roles and Permission and linking the two bounded contexts. In this scenario you could have a domain service that deals with the communication between the two. Call the Customer root with an operation and pass in the domain service for some intention revealing double dispatch and let the domain service resolve wheather that operation goes through or not. In this scenario though, the responsibilities of user auth is not the Customer's at all. The Customer simply doesn't care (because it cannot itself guarantee the transaction) and its up to User Auth and Roles to decide what to do.
From: Implementing Domain Driven Design - Vaughn Vernon
A properly designed Aggregate is one that can be modified in any way required by the business with its invariants completely consistent within a single transaction. And a properly designed Bounded Context modifies only one Aggregate instance per transaction in all cases. What is more, we cannot correctly reason on Aggregate design without applying transactional analysis.

Related

DDD Domain Entities using external Services

In DDD, you're strongly encouraged to have all business logic within the domain entities instead of separate from it. Which makes sense.
You also have the idea of Domain Services to encapsulate certain pieces of logic.
What I can't work out is how to have the domain entities perform their business logic that itself depends on external services.
Take, for example, a user management system. In this there is a User domain entity, on which there are various business actions to perform. One of these is verify_email_address - which sends an email to the users email address in order to verify that it's valid.
Except that sending an email involves interactions with external services. So it seems reasonable for this logic to be encapsulated within a Domain Service that the User entity then makes use of. But how does it actually do this?
I've seen some things suggest that the User entity is constructed with references to every domain service that it needs. Which makes it quite big and bloated, and especially hard to test.
I've seen some things that suggest that you should pass in the domain service to the method that you are calling - which just feels weird. Why would someone outside of the domain entity need to pass in the EmailClient service when calling verify_email_address?
I've also then seen the suggestion that you instead pass the User entity in to the domain service, except that this seems to imply that the logic is in the domain service and not the entity.
And finally, I've seen suggestions that the entity should raise a domain event to trigger the email, which the domain service then reacts to. That means that all of the logic for whether to send the email or not - no need if it's already verified - and which email address to send it to are in the right place, and it also means that the user only needs a way to raise events and nothing more. So it feels less tightly coupled. But it also means you need a whole eventing mechanism, which is itself quite complicated.
So, am I missing something here? How can I achieve this?
(I'm working in Rust if that matters, but I don't see that it should)
What I can't work out is the best way to have the domain entities perform their business logic that itself depends on external services.
That's not your fault; the literature is a mess.
In DDD, you're strongly encouraged to have all business logic within the domain entities instead of separate from it.
That's not quite right; the common idea is that all business logic belongs within the domain layer (somewhere). But that doesn't necessarily mean that the logic must be within a domain entity.
Evans, in Chapter 5, writes:
In some cases, the clearest and most pragmatic design includes operations that do not belong to any object. Rather than force the issue, we can follow the natural contours of the problems space and include SERVICES explicitly in the model.
There are important domain operations that can't find a natural home in an ENTITY or VALUE OBJECT....
It's a very Kingdom of Nouns idea; we have code that actually does something useful, so there must be an object it can belong to.
Having a module (in the Parnas sense) in the domain layer that is responsible for the coordination of an email client and a domain entity (or for that matter, a repository) to achieve some goal is a perfectly reasonable option.
Could that module be the domain entity itself? It certainly could.
You might find, however, that coupling the management of the in-memory representation of domain information and the orchestration of a domain process that interacts with "the real world", as it were, complicates your maintenance responsibilities by introducing a heavy coupling between two distinct concepts that should instead be lightly coupled.
Clean Architecture (and the predecessors in that lineage) suggests to separate "entities" from "use cases". Ivar Jacobson's Objectory Process distinguished "entities" from "controls". So the notion of a service that is decoupled from the entity shouldn't be too alien.
Ruth Malan writes:
Design is what we do when we want to get more of what we want than we'd get by just doing it.
Finding the right design depends a lot on finding the right "what we want" for our local context (including our best guess at how this local context is going to evolve over the time window we care about).
VoiceOfUnReason has a perfectly valid answer.
I just want to boil down your question to the grits.
What I can't work out is how to have the domain entities perform their business logic that itself depends on external services.
I've also then seen the suggestion that you instead pass the User entity in to the domain service, except that this seems to imply that the logic is in the domain service and not the entity.
That's the key. All logic that belongs to domain entities should be done on domain entities. But at the same time, domain entities MUST be independent of the outside world (even other domain entities).
That's why we have domain services and application services.
Domain services are used to coordinate things between multiple entities, like transferring money between two accounts:
public class TransferService
{
IAccountRepos _repos;
public void Transfer(string fromAccountNumber, string toAccountNumber, decimal amount)
{
var account1 = _repos.Get(fromAccountNumber);
var account2 = _repos.Get(fromAccountNumber);
var money = account1.Withdraw(amount);
account2.Deposit(money);
_repos.Update(account1);
_repos.Update(account2);
}
}
That's a domain service since it's still only using the domain only.
Application services on the other hand are used to communicate over boundaries and with external services.
And it's an external service that you should create in this case. It looks similar to domain services but are at a layer over it (it can use domain services to solve its purpose).
To summarize:
Entities must be used to perform actions on themself (the easiest way is to make all setters private which forces you to add methods).
Domains services should be used as soon as two or more entities must be used to solve a problem (can even be two entities of the same type as in the example above)
Application services are used to interact with things outside the domain and can use entities and/or domain services to solve the problem.

Should Commands always be a facade to domain models behavior in CQRS?

In a DDD-CQRS scenario, should my commands in the Application/Service layer always be just a facade to different aggregation methods? Or should commands retain business logic inside it (consequently transferring that logic from domain models to the commands)?
Commands are best thought of as Data Transfer Objects (DTO) - they transport data and intentions from the external world into the domain. They are intentions because the domain then decides to let the command through to execute or discard if it violates domain invariants.
Commands seldom contain business logic. They may contain validations to ensure the command itself is being expressed correctly and that it contains all necessary data in the right format, but that's about it. They rarely know of aggregate structures or the domain - they are dumb transports.
In reality, commands turn out to be quite distinct from aggregate structures you will eventually arrive at. They may not even map to any single aggregate. Executing a command may mean invoking an aggregate's method as part of the request, but the action may soon be followed by additional transactions on other aggregates (through domain events raised during the initial transaction) to make the system eventually consistent.
As a rule, you should only place business logic in the domain layer (Aggregates, Entities, Value Objects, Domain Services, and Domain Events). It is a code smell if you observe domain logic anywhere else, and code needs to be refactored.

How to handle relationships between aggregate roots in resolvejs

I'm having trouble figuring out how to handle some basic stuff around relationships between aggregate roots in resolvejs. The basic question is how do I handle the integrity of relationships? To do so, it seems like you need knowledge of both sides at the same time, but that doesn't seem to be allowed in the write side.
Heres the setup: I am trying to build a user management tool and I have two aggregate roots, User and Organisation. I need to allow both to exist independently of each other and define an access relationship between them (i.e. a user can have access to any number of organisation).
If the relationship belongs to the User, I can create a create a command like grantAccessToOrganisation on the User aggregate which takes an organisationId but this raises a couple questions. How do I make sure that the organisationId provided is real one? It seems like it needs to happen in the command handler but since the command belongs to the User aggregate, I don't have access to the Organisation aggregate. Also, how should I handle when an organisation gets removed? It seems like that should have a side effect on all users who have access to it but I don't seem to have a good way of making that query on the write side.
Try not to think of aggregate as an "entity" in traditional systems. Choose aggregate root as a transactional and consistency boundary.
This means that all commands to the given aggregate are sequental, its state is consistent, meaning you can be sure that your command is applied to expected aggregate state and no chages is being done by another user or process.
As an extreme example, you can even have a single aggregate "System", and the whole system state will be accessible to you. But this mean the size of the state will be enourmous, and each command will lock the whole system.
So choose your aggregate large enough to control its transactions and small enough not to block other transactions.
In your example, I can guess that User is more about identity, login, profile, avatar - things like that. It can live without knowledge of Organisation and access rights to it. Organisation is the aggregate that deals with access rights and changing access rights is a transaction that affect the single organisation.
So I would send grantAccess command to the Organisation, not to the user in your example. But of course it depends on other requirements, and I could be wrong here.
Also, there always will be some inter-aggregate business rules that can be implemented with saga. An example would be a rule that if User login is disabled, its access rights are removed after 30 days. Saga is a long-running business transaction that can affect several aggregates.

Specifications Pattern crossing bounded context - Domain Driven Design

I'm trying to understand and implement with good practice the Specification Pattern within my domain driven design project.
I have few questions:
For example: verifying that a customer is subscribed before update a data on a aggregate is it part of business rule and should sit in the domain layer?
Can specifications cross bounded context? For exemple, i have a Subscription bounded context where we can find a specification called SubscriptionIsActive. In a second bounded context let's call it PropertyManagement. I would like to call SubscriptionIsActive specification as an User need to be a subscriber to create a Property aggregate. My specification here is crossing bounded context and i don't think it's right choice, any recommandation, tips?
Where should instanciate the specification when we want to use it, Application layer (that contains, commands and query, we use cqrs) or Domain Layer wihtin the aggregate root?
At the end, where should access control like (User has rights to edit some aggregate) sit in a domain driven design, Domain Layer or Application Layer in services before calling the aggregate?
Thanks
My recommendation is that a domain should not call out to obtain additional information/data. This means that everything a domain needs should be handed to it and the domain performs the transactional processing.
All authentication/authorization takes place outside the domain and access to the relevant domain operations is granted based on the identity/access outcome.
I have found specifications most useful on the data querying side of things. Usually there are multiple permutations w.r.t. how data is retrieved and a specification encapsulates the various possibilities quite nicely (GetByName,GetByNameAndType,etc.) This doesn't mean that you cannot use a specification in the domain. You may have some complex piece of functionality to determine qualification of a domain object and in that case a specification operating on the relevant domain object would be a good fit. To that end a specification doesn't cross a domain as it would be part of a particular domain. In much the same way as a specification is useful in a data querying scenario you may have a specification in the integration/application concern and have it determine qualification based on data from multiple domains such as in your second example. This may even be something that is applied in a process manager implementation (integration).
Not all business rules need to be specifications and if, as in your first case, a customer is not subscribed then your integration/application processing would stop any further transactional changes much as it would for an authorization failure.

Validating domain object properties in the Application layer. Is it okay?

In DDD, the Application layer is supposed to just perform coordination tasks, whereas the Domain layer is responsible of validating the business rules.
My question is about validating the domain object properties. For example, I need to validate that a required property has some value in it before persisting it to the database through repositories.
In terms of DDD, is it acceptable to perform this sort of property validation in the Application layer?
Kinds of validation
In the situation you describe, there are two different validation steps that you need to consider separately:
Input validation. This is the responsibility of an app service. The goal is to ensure that no garbage or harmful data enters the system.
Protecting model invariants. This is your domain logic. Whenever something in the domain changes, you need to make sure that the changes are valid within your domain, i.e. all invariants still hold.
Validating domain invariants as part of an app service
Note that sometimes you also want to validate domain invariants in an app service. This could be necessary if you need to communicate invariant violations back to the client. Doing this in the domain would make your domain logic client-specific, which is not what you want.
In this situation, you need to take care that the domain logic does not leak into the app service. One way to overcome this problem and at the same time make a business rule accessible to both the domain and the app service is the Specification Pattern.
Here is an answer of mine to another question that shows an example implementation for the specification pattern.
You can validate incoming data in your ui layer.
For example you can you symfony forms validation or just check for necessary data inside your layer with Rest.
What about Domain Layer, it depends.
You didn't precise what kind of domain object it is.
Mostly you do such kind of validation by creating Value Object, with creation logic inside. For example Email Value Object, you can't create wrong one, otherwise it will throw exception.
Aggregates can perform validation before executing method and it's called invariants. For example, user has method becomeVIP, inside a method there is constraint, that only user with name 'Andrew', can become a VIP.
So you don't do validation after the action, but before the action. You don't let your aggregate go into wrong state.
If you have logic, which is not correlated with aggregate you put it in domain service, for example email uniqueness check.
Rather than "validating hat a required property has some value in it" at the periphery of the Domain, I prefer to make sure that it can never become null in the Domain the first place.
You can do that by forcing consumers of the constructors, factories and methods of that entity to always pass a value for the property.
That being said, you can also enforce it at the Application level and in the Presentation layer (most web application frameworks provide convenient ways of checking it these days). Better 2 or 3 verifications than one. But the domain should be the primary source of consistency.

Resources