i have a question related to read models in cqrs.
Assume we have two bounded contexts: A and B
In context A we build a readmodel based on the events from context A. We have some kind of dao to access the readmodel in A.
Now assume that B needs the same read model as A.
As far as i understood, bounded context shouldn't depend on each other.
So how can i use the model from A. I see three possiblities to solve this
Create an API Module for the read model in A and use this in context B
(Would be a dependency between A and B)
Create an seperate read model in context B thats exactly the same as in A
(Would result in code duplication)
Create a service facade (REST or SOAP or whatever) in B that is accessible from A to provide the read model
(possibly the service doesnt provide exactly the data needed)
Your read models don't belong to any bounded contexts, they are produced by some domain objects in some bounded context. But they are a separate component of your system.
Your bounded context shouldn't need any read model. Read model is an output of the domain, not the input. If you need 2 BC communicate, use events, not read models. Read models are for GUI/reporting, not for processing business rules.
It's actually very common to have dependencies between contexts, see relationships and context mapping in the DDD Reference.
In your example, context B depends on context A. Depending on the type of relationship (upstream-downstream, partnership, ...) context A decides how to let context B integrate with them (open-host, customer/supplier, ...).
Context A can provide a read model, events, or both. Integrating via events gives you independence, though integrating via a read model might be more practical for your example (but might cause friction once context A decides to diverge). Factors to take into account are your relationship with the other context, and the probability of change vs. cost of change.
Related
Imagine we have a microservice M1 with an aggregate root called Player and a microservice M2 with an aggregate root called Classification, now in the M1 we need to do some logic based on some property from Classification, now some steps to do that are:
Replicate the list of possible Classifications to M1 via asynchronous messaging;
Do what is asked by the business in M1;
Ok, now imagine we have a view to add Players, and in that view is possible to choose the Classification of the new Player from a dropdown list. Now the question:
Should the dropdown list be populated with the Classifications that were replicated into M1 or from M2?
As you can see, by using the data from M1 we would have to expose the Classification from M1 via an API, thus the title of the question.
EDIT
The replications happens through async messaging using events, so I'm not exposing the entire aggregate to M1 just some properties like an Id and the Description of the classification.
I believe both can be done and one is not better than the other. Either ways, you're making API call to M2 to get the classification. But this scenario is now telling you that the service boundary might be wrong - the vertical slice on the view to create a new player perhaps should be a single micro-service. Of course, you will add some fallback mechanism for the call to M2 so that in case of failure to M2, M1 doesn't fail completely (in this case, to create a new player).
You should treat each microservice as a service boundary. Means no aggregates ever leave the bounded context. The reason for this is, if you do that your leak your domain knowledge into other bounded contexts and have a hard dependency on it. Any change on the aggregate will break any depending service.
If you need to retrieve data from other bounded context you should do that through an anti-corruption layer. In terms of Microservices that can be translated into DTOs. This way when you add or remove a property you don't necessary break the contracts with the outside contexts.
From the provided information its hard to tell if Player and Classification belong to the same context or not. Basically there's nothing wrong to compose your UI data from multiple microservices (i.e. displaying orders and delivery notes on the same UI form, whereas they come from different bounding contexts, namely order and logistics).
However if your Player model/aggregates directly depend on each other and neither of them can be used independently of the other one, then its very likely its part of the same bounded context.
The main idea when you design your microservices is that one microservice should not make any synchronous calls to any other microservice. This implies that every microservice should gather any required external state in an asynchronous mode, before it will answer to queries or execute commands. One way to do that is (1) by subscribing to events; the other way (2) is by periodically querying some exposed Read-model (see CQRS), i.e. in a cron job.
In any case, you should not expose the entire Aggregate, otherwise you risk to break its encapsulation by depending on its internals. Instead, you should publish its domain events (1) or create a specially designed canonical Readmodel that present the most probable model to the other microservices; something like a canonical Read-model; I would avoid this unless the domain is too simple, too CRUD.
i'm trying to apply the domain driven design in a little project
i want to separate the authentication of rest of the users logic,
i'm using a value object for the id (userID) in the beginning i have the userID in the same level(package) of the users but I realize when i separate bounded context for authentication and user, they share a common value object for the userID, so my question is where supose that i have to put the common or share value objects? is correct if i created a packages called commons?
It is recommended to not share models between bounded contexts, however, you can share IDs and even simple Value objects (like Money).
The general rule is that you may share anything that is immutable or that changes very infrequently and IDs rarely change structure (here immutability refers to the source code and value immutability).
Packages called "common" usually refers to reusable concepts that you use in your projects, so that you don't have to code them in every project. There it's usual to put base abstract objects and interfaces, for entities, value objects, etc.
But it's not your case about userId. What you are saying is to put userId in a "shared kernel" model. It is an option, but usually it is not recommended.
From my point of view:
The auth BC has the concepts id,login,password,role,etc.
The user BC has concepts like name,surname,address,age,etc, but it also has to have the id, that it gets from auth BC.
From what I know, you have 2 options:
(1) Authentication BC shares "id" concept explicitly, i.e. it has a shared kernel. So "id" concept would belong to user BC model too.
(2) Authentication BC is a generic BC. So you have to integrate the user BC with the auth BC to get the id from it.
First of all, I personally see this as an context mapping question at code level, where you are effectively looking to have a shared kernel between multiple bounded contexts.
This depends on the business really. You typically need to consider the following questions:
How do different teams responsible for each bounded context collaborate with each other? If it's 1 team maintaining all the related bounded contexts, it might be OK, but it's multiple teams have different objectives, it leads to the next point.
How do you plan to maintain this shared kernel over time? In general, this shared kernel will need to change to adapt to business changes.
For more detailed arguments, there are plenty of resources out there about context mapping, such as Vaughn Vernon's book "Implementing Domain Driven Design".
I've been reading Eric Evans' DDD: Tackling Complexity in the Heart of the Software and in the section in context maps, Evans cited an example of 2 bounded contexts (Booking context and Network Traversal Service) using a translator to integrate them.
If I understand correctly, when we create a model, we put everything into bounded contexts creating conceptual boundaries for the domain. My questions are:
If everything should be in a bounded context, where should the translator be located? In Evans' sample diagram, the translator is outside (in between) both bounded contexts.
Say we have a single team working on a ERP. Should the ERP be put in several bounded contexts or a single one only. Based on Evans' sample, the bounded contexts were devised so that multiple teams could work on their own model. But since this is a single team, wouldn't they benefit on a single model so integration wouldn't be an issue? Or did I understand this wrong?
In question 2's case, if multiple bounded contexts, what if in implementation, we need a class from Accounting to be used in Payroll? I don't think we need a translator here but I'm not sure how to share the required class. Will just referencing the needed class from another bounded context be fine?
And lastly, how is a module in DDD related to a bounded context?
In an Infrastructure layer (outside the Domain), it's a technical detail.
A bounded context(BC) emerges from the Domain, that's why we identify them and not defining them. Once identified, if there are many BCs and there are developers available then the workload can be split so that the app can be developed faster. A single model is not advisable, you want a single domain model per BC and also a simplified read model for querying (CQRS).
I don't know but for me Payroll is part of Accounting, there aren't really 2 BC. Account is a BC, however other BC might need a Payroll but that definition is specific to the BC. And probably the definition is just really some data (a read model). Payroll behaviour should stay in Accounting. So you need to have clearly defined what each BC understands by "Payroll". Usually you'll have a domain service who will use concepts from both BC and which will use the 'translator'.
It isn't. A module just groups things together from a technical point of view. A BC is pretty virtual, you might choose to have a project or a module corresponding to one BC but that's your decision how to organize things.
If everything should be in a bounded context, where should the translator be located? In Evans' sample diagram, the translator is
outside (in between) both bounded contexts.
I think this question has no sense. Each BC is a boundary in wich a domain model exist, and the boundary is determined by the UL, each BC has its own UL. If you just create one model, you don't need translation. Instead of spliting a big model into several smaller ones, you are joining them.
Say we have a single team working on a ERP. Should the ERP be put in several bounded contexts or a single one only. Based on Evans'
sample, the bounded contexts were devised so that multiple teams could
work on their own model. But since this is a single team, wouldn't
they benefit on a single model so integration wouldn't be an issue? Or
did I understand this wrong?
I think you understood wrong. You split a single model into several BCs according to the UL, not to the available teams. Then if you don't have enough teams for the number of BCs created, a team will have to develop more than one BC. By the way, the opposite is not desirable, i.e., a BC shouldn't be developped by more than one team.
In question 2's case, if multiple bounded contexts, what if in implementation, we need a class from Accounting to be used in Payroll?
I don't think we need a translator here but I'm not sure how to share
the required class. Will just referencing the needed class from
another bounded context be fine?
You shouldn't reference a domain object of another BC. That BC should protect its domain model, that's the application layer for. The application layer expose DTOs, plain objects, it shouldn't expose the domain model to the outside world. What you are asking for is a shared kernel (a model shared by other BC).
And lastly, how is a module in DDD related to a bounded context?
A module is just a java package, useful for keeping together things that a related to each other. So you split the source code of a BC in modules. Do it according to the UL, not to technical aspects. For instance, a module for each aggregate, not a module for entities, another one for repositories, etc.
Suppose you've got two aggregates in your bounded context which have some constraints amongst each other. Using DDD these inter aggregate constraints can't be enforced in the same transaction i.e. the aggregate boundaries are transactional boundaries.
Would you consider using what in the Microsoft CQRS journey is called a "process manager" to coordinate two aggregates in the same bounded context or is a process manager only used to coordinate between two bounded contexts? What would the equivalent of a process manager that coordinates two or more aggregate roots within the same bounded context be?
An aggregate root defines a bounded context by default, albeit a lower level one (btw the lowest level bounded context you can find is an object, any object). The process manager is the name they used instead of a saga, proabably you can come up with other names too, it doesn't matter, they all have the same purpose.
And yes, I would consider using a saga to achieve eventual consistency. In fact, I think this is the best way and this is exactly what I'm doing in my own apps. Anyway, I'm using a message driven architecture (yes, in a local, non-distributed application) and I have automatically saga support via the service bus (my own, not released yet).
What is important when dealing with eventual consistency is to ensure idempotency everywhere. That is the aggregate roots should reject a duplicate operation and of course the event handler should be able to cope with the fact that the same event can be published more than once. However, be aware that you can't guarantee 100% idempotency but you can get very close to.
I am fairly new to DDD and here is my dilemma:
I have to persist an entity A that has a reference to entity B (let us consider both are entity roots). The UI layer gathers all these info (at controller) through A_DTO (DTO class for A), maps the attributes to a new instance of A from the DTO, now for the reference to B in A , UI sends an id. As I am using an ORM behind the repositories I would want to lookup for the object instance of B from BRepository , populate the reference on the new A instance that we are building and finally call ARepository.save(A instance).
I have a few options here
Do all these in UI layer(either in controller or some kind of service facade) or
Do this in a ApplicationService called createA or even a domain Service .
Which of options will be correct ??. Here what really stands out is the process of looking up of B by its id to get the reference to set on A object, this can be equally argued as process to keep ORM satisfied or to keep the domain model consistent. There might be some implicit business rules and validations around the process of setting reference of B on A, these I think are the driving points for the decision here.
Also what could queer the pitch further here will be a consideration for validations, should validations be weaved in the process of creation of an entity and say the constructors and/or setters through specific errors that can be bubbled to the client through UI and have another level of validatins through repos ?? or as an explicit step happening in the controllers ??
The DTO is merely a convenience class for transporting data within the UI layer. The fact that you use an ID to refer to B is an implementation detail of the UI layer. So it should be the job of the UI layer / controller to map the DTO to a domain object, including translating IDs to references.
Validation, on the other hand, belongs rightly in the domain layer. In this regard, the only job of the UI is to set values in the domain object and display any errors arising from this.
Both options can be viewed as correct, but I tend to prefer option 2 because the encapsulation provided by application services helps in reading and understanding the code. It also makes it easier to consolidate the API of your domain. The argument in favor of option 1 over 2 is that the additional layer of encapsulation resulting from use of application services is needless complexity, though of course you be the judge. Validation is usually manifested in several layers of a application, including the presentation layer and the domain layer. It seems ideal to write validation logic once and have it reused everywhere else, in practice it is usually easier to duplicate validation logic. That means the the presentation layer, such as ASP.NET MVC, has its own validation declarations for view models. Then the application service and domain entities should also perform any validation that is needed in that context. Take a look at my posts on services in DDD as well as validation in DDD for in depth discussion on these topics.