I'm facing an case with my new microservice application.
I have an Entity as users (An single table, but different roles).
consider i have roles as manager and reader, And one more entity as
Book.
Where the manager can assign Books to readers, And i have Microservices as usermS, bookmS.
When i want to get all the readers of Book-A, the API will go in to bookmS, but the user details are still with the usermS.
And also combined searches.
I'm more worried about the paginations and search for the readers, if the readers for a Book keeps increasing. Expected to get roles in future.
My ddd vision of your problem:
You have 2 bounded contexts, each one a microservice, and you have to integrate both of them translating concepts:
Identity and access management (IAM). Here you have the concepts of users and roles.
Library: Here you have the concepts of managers and readers, which are roles in IAM.
Regarding searches and information about readers, in the IAM bounded context you have the login name and the password for example, but IAM doesn't know about other details of a reader.
UPDATE: About duplication of data
In your comment https://stackoverflow.com/posts/comments/101968503?noredirect=1 , you mean duplicated data across different entities inside the same BC don't you? For example, having an email in Reader and Manager entities? You could do an abstract base entity with the common data, and both entities inherit from it. This is the approach in Vaughn Vernon's book.
The duplication of data just exists across different BCs if you go for an async integration. But there's no denormalization, each BC has its own database, and each database is normalizated.
Library BC (downstream) and IAM BC (upstream) are enventually consistent. Library BC will listen to IAM BC events, and will update its database. This means a delay that it is supposed you can live with. Regarding email, I wouldn't allow to modify it, since it is the login for the user, but that's just my opinion.
If you don't want to duplicate data across BCs, or you cannot live with the update delay in the downstream BC, you could go for a sync integration. So that everytime the Library BC needs data from the IAM BC, it calls an http rest api that IAM BC offers, and waits for the response.
Lets first break down your problem:
start with the easy one:
When i want to get all the readers of Book-A, the API will go in to bookmS, but the user details are still with the usermS.
your doubt here is how to show the user details from the bookms?
there are two options :
When some user becomes a reader of your book save user name and email type of details in the reader object in bookms so that you could shown them , also listen to event of user detail change from userms so that you could update the readers.
good part here is that there is no dependency between userms and bookms.
bad part here is that you may need to update multiple reader entity when a user detail changes, small optimizations here is just update in the read model.
get data first from bookms and then from userms .
good part : no event listening , always consistent data.
bad part: high dependency between bookms and userms and And also combined searches.
i would have gone with the first approach assuming user dosen't change the basic details on which you need to show data very frquently.
SECOND QUESTION:
How to break the system using DDD?
In this the first answer written given right direction to it. i just want to add a bit more.
You should consider manager and reader as entity in bookms and not as roles.
Reason from DDD and in general:
In General: A user could be managing a book and as well a reader .
DDD: Manager and Reader are notions which bookms (which actually should be named libraryms ) are part of the domain entity.
So your solutions would be:
userms :
user: person which has access to library and can apply for being a manager or a reader. there could be two roles - student , admin .
libraryms:
Manager Entity - users which are allowed to subscribe a book to readers.
ReaderEntity - any user which has taken a book subscriptions
BookEntity - represents a book registered in the library
BookSubscriptionEntity - its your choice, you could use the BookEntity but i would prefer this.
Now by separating the role as admin and manager as entity you achieved two things.
One is now a admin could be a reader as well and a student can be a manager as well.Also library microservice works according to DDD , easy to understand and some api like assign book to reader dosent need to check anyhthing from userms
Related
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.
Here's an abstract question with real world implications.
I have two microservices; let's call them the CreditCardsService and the SubscriptionsService.
I also have a SPA that is supposed to use the SubscriptionsService so that customers can subscribe. To do that, the SubscriptionsService has an endpoint where you can POST a subscription model to create a subscription, and in that model is a creditCardId that points to a credit card that should pay for the subscription. There are certain business rules that say whether or not you can use said credit card for the subscription (expiration is more than 12 months away, it's a VISA, etc). These specific business rules are tied to the SubscriptionsService
The problem is that the team working on the SPA want a /CreditCards endpoint in the SubscriptonsService that returns all valid credit cards of the user that can be used in the subscriptions model. They don't want to implement the same business validation rules in the SPA that are in the SubscriptionsService itself.
To me this seems to go against the SOLID principles that are central to microservice design; specifically separation of concerns. I also ask myself, what precedent is this going to set? Are we going to have to add a /CreditCards endpoint to the OrdersService or any other service that might use creditCardId as a property of it's model?
So the main question is this: What is the best way to design this? Should the business validation logic be duplicated between the frontend and the backend? Should this new endpoint be added to the SubscriptionsService? Should we try to simplify the business logic?
It is a completely fair request and you should offer that endpoint. If you define the rules for what CC is valid for your service, then you should offer any and all help dealing with it too.
Logic should not be repeated. That tend to make systems unmaintainable.
This has less to do with SOLID, although SRP would also say, that if you are responsible for something then any related logic also belongs to you. This concern can not be separated from your service, since it is defined there.
As a solution option, I would perhaps look into whether I can get away with linking to the CC Service since you already have one. Can I redirect the client with a constructed query perhaps to the CC Service to get all relevant CCs, without actually knowing them in the Subscription Service.
What is the best way to design this? Should the business validation
logic be duplicated between the frontend and the backend? Should this
new endpoint be added to the SubscriptionsService? Should we try to
simplify the business logic?
From my point of view, I would integrate "Subscription BC" (S-BC) with "CreditCards BC" (CC-BC). CC-BC is upstream and S-BC is downstream. You could do it with REST API in CC-BC, or with a message queue.
But what I validate is the operation done with a CC, not the CC itself, i.e. validate "is this CC valid for subscription". And that validation is in S-BC.
If the SPA wants to retrieve "the CCs of a user that he/she can use for subscription", it is a functionality of the S-BC.
The client (SPA) should call the the S-BC API to use that functionality, and the S-BC performs the functionality getting the CCs from the CC-BC and doing the validation.
In microservices and DDD the subscriptions service should have a credit cards endpoint if that is data that is relevant to the bounded context of subscriptions.
The creditcards endpoint might serve a slightly different model of data than you would find in the credit cards service itself, because in the context of subscriptions a credit card might look or behave differently. The subscriptions service would have a creditcards table or backing store, probably, to support storing its own schema of creditcards and refer to some source of truth to keep that data in good shape (for example messages about card events on a bus, or some other mechanism).
This enables 3 things, firstly the subscriptions service wont be completely knocked out if cards goes down for a while, it can refer to its own table and work anyway. Secondly your domain code will be more focused as it will only have to deal with the properties of credit cards that really matter to solving the current problem. Finally if your cards store can even have extra domain specific properties that are computed and materialized on store.
Obligatory Fowler link : Bounded Context Pattern
Even when the source of truth is the domain model and ultimately you must have validation at the
domain model level, validation can still be handled at both the domain model level (server side) and
the UI (client side).
Client-side validation is a great convenience for users. It saves time they would otherwise spend
waiting for a round trip to the server that might return validation errors. In business terms, even a few
fractions of seconds multiplied hundreds of times each day adds up to a lot of time, expense, and
frustration. Straightforward and immediate validation enables users to work more efficiently and
produce better quality input and output.
Just as the view model and the domain model are different, view model validation and domain model
validation might be similar but serve a different purpose. If you are concerned about DRY (the Don’t
Repeat Yourself principle), consider that in this case code reuse might also mean coupling, and in enterprise applications it is more important not to couple the server side to the client side than to
follow the DRY principle. (NET-Microservices-Architecture-for-Containerized-NET-Applications book)
Which is suggested way to implement _customRoleRepository in the following examples?
Following code is executed in the application service.
var user = _userRepository.GetById(1);
var customRole = _customRoleRepository.GetById(user.CustomRoleId);
or
var user = _userRepository.GetById(1);
var customRole = _customRoleRepository.GetForUser(user);
Given the two options I would probably go for the first one, which keeps consistency of accessing by an ID.
If possible, it might be preferable to load the custom role when you load the user to avoid another round trip to the database, especially if this is a common operation. This could be implemented as a read model.
This is presuming you have modelled your aggregates correctly... :)
Hate to say it but in a DDD environment, my answer would be neither.
In your first example, the role repository can be ignorant of the user domain which is good but it means the application needs to know that to get the role it needs to pull an id out of the user and then query another repository. In other words, the application is acting as a mapper between user and role.
In the second example, the roles repository now needs to know about the user domain. Not great but on the other hand the application no longer needs to know about roleId. So that is good. Classic sort of trade off between the two approaches.
But in both cases the application still needs two repositories to get it's information. What happens when more relations are needed? The number of repositories can quickly grow and things become a mess.
In Domain Driven Design you should try to think in terms of aggregate roots(AR) and domain contexts. For your example context, the user is an AR and the role becomes a child. So you might have:
var user = _userFinder.GetById(1);
var customRole = user.CustomRole;
That hides most of the implementation details from you application and allows you to focus on what your domain entities actually need to do.
Both are equally valid, depending on your needs. GetForUser would be good if you want to ensure the calling code has a valid User aggregate before you try and retrieve the roles - while it does couple the customRoleRepository to knowledge of the User aggregate, if you want to require the calling code to have a valid User aggregate, then that coupling has a purpose.
GetByUserId is more consistent with GetById and has less coupling, so if in your context it doesn't matter to call GetByUserId even if the client doesn't have a valid User aggregate, then that's fine too.
If you are loading ById, I've also found using typed identity valueobjects can be quite helpful in providing an extra level of type safety - some conversation about the pros and cons here https://stackoverflow.com/a/5377460/6720449 and here https://groups.google.com/forum/#!topic/dddcqrs/WQ9zRtW3Gbg
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.
Despite having studied Domain Driven Design for a long time now there are still some basics that I simply figure out.
It seems that every time I try to design a rich domain layer, I still need a lot of Domain Services or a thick Application Layer, and I end up with a bunch of near-anemic domain entities with no real logic in them, apart from "GetTotalAmount" and the like. The key issue is that entities aren't aware of external stuff, and it's bad practice to inject anything into entities.
Let me give some examples:
1. A user signs up for a service. The user is persisted in the database, a file is generated and saved (needed for the user account), and a confirmation email is sent.
The example with the confirmation email has been discussed heavily in other threads, but with no real conclusion. Some suggest putting the logic in an application service that gets an EmailService and FileService injected from the infrastructure layer. But then I would have business logic outside of the domain, right? Others suggest creating a domain service that gets the infrastructure services injected - but in that case I would need to have the interfaces of the infrastructure services inside the domain layer (IEmailService and IFileService) which doesn't look too good either (because the domain layer cannot reference the infrastructure layer). And others suggest implementing Udi Dahan's Domain Events and then having the EmailService and FileService subscribe to those events. But that seems like a very loose implementation - and what happens if the services fail? Please let me know what you think is the right solution here.
2. A song is purchased from a digital music store. The shopping cart is emptied. The purchase is persisted. The payment service is called. An email confirmation is sent.
Ok, this might be related to the first example. The question here is, who is responsible for orchestrating this transaction? Of course I could put everything in the MVC controller with injected services. But if I want real DDD all business logic should be in the domain. But which entity should have the "Purchase" method? Song.Purchase()? Order.Purchase()? OrderProcessor.Purchase() (domain service)? ShoppingCartService.Purchase() (application service?)
This is a case where I think it's very hard to use real business logic inside the domain entities. If it's not good practice to inject anything into the entities, how can they ever do other stuff than checking its own (and its aggregate's) state?
I hope these examples are clear enough to show the issues I'm dealing with.
Dimitry's answer points out some good things to look for. Often/easily you find yourself in your scenario, with a data shoveling from db up to GUI through different layers.
I have been inspired by Jimmy Nilsson's simple advice "Value objects, Value objects and more Value objects". Often people tend to focus to much on Nouns and model them as entity. Naturally you often having trouble in finding DDD behavior. Verbs are easier to associate with behavior. A good thing is to make these Verbs appear in your domain as Value objects.
Some guidance I use for my self when trying to develop the domain (must say that it takes time to construct a rich domain, often several refactoring iterations...) :
Minimize properties (get/set)
Use value objects as much as you can
Expose as little you can. Make you domain aggregates methods intuitive.
Don't forget that your Domain can be rich by doing Validation. It's only your domain that knows how to conduct a purchase, and what's required.
Your domain should also be responsible for validation when your entities make a transition from one state two another state (work flow validations).
I'll give you some examples:
Here is a article I wrote on my blog regarding your issue about anemic Domain http://magnusbackeus.wordpress.com/2011/05/31/preventing-anemic-domain-model-where-is-my-model-behaviour/
I can also really recommend Jimmy Bogard's blog article about entity validations and using Validator pattern together with extension methods. It gives you the freedom to validate infrastructural things without making your domain dirty:
http://lostechies.com/jimmybogard/2007/10/24/entity-validation-with-visitors-and-extension-methods/
I use Udi's Domain Events with great success. You can also make them asynchronous if you believe your service can fail. You also wrap it in a transaction (using NServiceBus framework).
In your first example (just brainstorming now to get our minds thinking more of value objects).
Your MusicService.AddSubscriber(User newUser) application service get a call from a presenter/controller/WCF with a new User.
The service already got IUserRepository and IMusicServiceRepository injected into ctor.
The music service "Spotify" is loaded through IMusicServiceRepository
entity musicService.SignUp(MusicServiceSubscriber newSubsriber) method takes a Value object MusicServiceSubscriber.
This Value object must take User and other mandatory objects in ctor
(value objects are immutable). Here you can also place logic/behavior like handle subscriptionId's etc.
What SignUp method also does, it fires a Domain Event NewSubscriberAddedToMusicService.
It get caught by EventHandler HandleNewSubscriberAddedToMusicServiceEvent which got IFileService and IEmailService injected into it's ctor. This handler's implementation is located in Application Service layer BUT the event is controlled by Domain and MusicService.SignUp. This means the Domain is in control. Eventhandler creates file and sends email.
You can persist the user through eventhandler OR make the MusicService.AddSubscriber(...) method to this. Both will do this through IUserRepository but It's a matter of taste and perhaps how it will reflect the actual domain.
Finally... I hope you grasp something of the above... anyhow. Most important is to start adding "Verbs" methods to entitys and making the collaborate. You can also have object in your domain that are not persisted, they are only there for mediate between several domain entities and can host algorithms etc.
A user signs up for a service. The user is persisted in the
database, a file is generated and saved (needed for the user account),
and a confirmation email is sent.
You can apply Dependency Inversion Principle here. Define a domain interface like this:
void ICanSendConfirmationEmail(EmailAddress address, ...)
or
void ICanNotifyUserOfSuccessfulRegistration(EmailAddress address, ...)
Interface can be used by other domain classes. Implement this interface in infrastructure layer, using real SMTP classes. Inject this implementation on application startup. This way you stated business intent in domain code and your domain logic does not have direct reference to SMTP infrastructure. The key here is the name of the interface, it should be based on Ubiquitous Language.
A song is purchased from a digital music store. The shopping cart
is emptied. The purchase is persisted. The payment service is called.
An email confirmation is sent. Ok, this might be related to the first example. The question here is, who is responsible for orchestrating this transaction?
Use OOP best practices to assign responsibilities (GRASP and SOLID). Unit testing and refactoring will give you a design feedback. Orchestration itself can be part of thin Application Layer. From DDD Layered Architecture:
Application Layer: Defines the jobs the software is supposed to do and directs the
expressive domain objects to work out problems. The tasks this layer
is responsible for are meaningful to the business or necessary for
interaction with the application layers of other systems.
This layer is kept thin. It does not contain business rules or
knowledge, but only coordinates tasks and delegates work to
collaborations of domain objects in the next layer down. It does not
have state reflecting the business situation, but it can have state
that reflects the progress of a task for the user or the program.
Big part of you requests are related to object oriented design and responsibility assignment, you can think of GRASP Patterns and This, you can benefit from object oriented design books, recommend the following
Applying UML and Patterns