Each of our bounded contexts has an event message processor which pulls messages off the inter-context-bus and dispatches it locally via an in-memory bus (Reactive Extensions, or https://github.com/flq/MemBus).
In DDD books I have read it talks about putting messages in modules within the project such as mycompany.accounts.infrastructure.messages and mycompany.ordering.infrastructure.messages .
The problem for me with multiple contexts, referencing these messages would lead to circular references.
How best to organise different bounded context messaging contracts:
Would each bounded context have a separate project that contained all of the possible messages for that context so that other bounded contexts could reference?
Or is it better to have separate shared library for all messages that will go over the inter-context-bus?
I solve similar problems building (at least) two assembly for each bounded context:
One for the contracts (event, exceptions, shared identifiers and so on...)
One for the implementation of entities.
This way, different bounded contexts implementations can reference to the same contracts, without any cicle.
edit
As for naming conventions, I usually name assemblies after the "conventional name" of the bounded context, for example
BankName.FinancialAdvisory for the contracts
BankName.FinancialAdvisory.POCO for the implementations
BankName.FinancialAdvisory.ORMOrOtherTechnologicalCouplingName when I need to specialize some class to use them in a specific technological environment.
However, inside the POCO assembly the root namespace is the same of the contracts' one (eg BankName.FinanicalAdvisory): this because the POCOs, that expresses the business rules in code without any technological concern, have the same development livecycle of the contracts. On the contrary the assembly containing technological specializations uses a root namespace that is equals to the assembly name (such as BankName.FinancialAdvisory.ORMOrOtherTechnologicalCouplingName).
Nevertheless all the assembly related to the domain share the same namespace structure: for example if a namespace "Funds" exists under BankName.FinancialAdvisory it also exists in both POCO and ORMOrOtherTechnologicalCouplingName (if it contains any class, of course).
Related
When building an event store, the typical approach is to serialize the event and then persist the type of the event, the body of the event (the serialized event itself), an identifier and the time it occurred.
When it comes to the event type, are there any best practises as to how these should be stored and referenced? Examples I see store the fully qualified path of the class ie.
com.company.project.package.XXXXEvent
What effort is then required though if you decide to refactor your project structure?
After years running event-sourced applications in production, we avoid using fully qualified class names or any other platform-specific identifiers for event types.
An event type is just a string that should allow any kind of reader to understand how the event should be deserialized. You are also absolutely right about the issue with refactoring the application structure that might lead to changes in the class name.
Therefore, we use a pre-configured map that allows resolving the object type to a string and to reverse the string to an event type. By doing so, we detach the event type meta from the actual class and get the freedom to read and write events using different languages and stacks, also being able to freely move classes around of needed.
What effort is then required though if you decide to refactor your project structure?
Not a lot of effort, but some discipline.
Events are messages, and long term viability of messages depend on having a schema, where the schema is deliberately designed to support forward and backward compatibility.
So something like "event type" would be a field name that can be any of an open set of identifiers which would each have an official spelling and semantics.
The spelling conventions that you use don't matter - you can use something that looks like a name in a hierarchical namespace, or you can use a URI, or even just a number like a surrogate key.
The identifiers, whatever convention you use, are coupled to the specification -- not to the class hierarchy that implements them.
In other words, there's no particular reason that org.example.events.Stopped necessarily implies the existence of a type org.example.events.Stopped.
Your "factories" are supposed to create instances of the correct classes/data structures from the messages, and while the naive mapping from schema identifier to class identifier works, then yes, they can take that shortcut. But when you decide to refactor your packages, you have to change the implementation of the factory such that the old identifiers from the message schema map to the new class implementations.
In other words, using something like Class.forName is a shortcut, which you abandon in favor of doing the translation explicitly when the short cut no longer works.
Since event sourcing is about storing Domain Events, we prefer to avoid package-names or other technical properties in the events. Especially when it comes to naming them, since the name should be part of ubiquitous language. Domain Experts and other people don't lean on package names when making conversation about the domain. Package names are a language construct that also ties the storage of the Domain Events with the use of them within your software, which is another reason to avoid this solution.
We sometimes use the short class name (such as Class.forName in Java) to make mapping to code simpler and more automatic, but the class names should in that case be carefully chosen to match the ubiquitous language so that it still is not too implementation-specific.
Additionally, adding a prefix opens upp the possibility to have multiple Event Types with the same name but using different prefixes. Domain Events are part of the context of the Aggregate they are emitted from and therefore the Aggregate type can be useful to embed in the event. It will scope your events so you don't have to make up synthetic prefixes.
If you store events from multiple bounded contexts in one store, BoundedContext.EventThatHappened. Past tense for events, and event names are unique for a bounded context. As your events will change implementation, there is no direct connection to a class name.
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".
Say I have an object that for the most part has necessary attributes, etc for two different apps because both apps have the need to use them. It's possible that 10% of the attributes won't' be used in one app. Is it better to share that object (and aggregate/bounded context as a shared kernel?) or duplicate the attributes and data that is stored? One app is for end users/activities and the other app is for the management of the users/activities.
We recently developed an application that involved several modules using a lot of common entities. When we developed them, we moved these common entities to a project called common-domain and then had all the dependent modules use it. It turned out to be a disaster.
While we initially found several attributes to be common, we found out that how we designed them for certain modules conflicted in how they were used for the others. Altering the entities in the common-domain to fit the needs of one module sometimes broke how they worked for the other modules. We did not use a test-driven approach and it made finding the resulting bugs tedious.
Learning from that mistake, we should have recognized and identified the bounded contexts and identified the entities and their associated attributes per bounded context. The "common" entity should have been defined per bounded context along with any attribures that are needed for that context. Some attributes will definitely be common but since they are separate bounded contexts, they have to be declared per entity per bounded context.
I'll go a little bit further to mention where an item can be shared. Each entity in a bounded context has its own repository. It is possible that the "common" entities share the same underlying database table. It is the responsibility of each BC's entity repository to retrieve the relevant columns in order to return the appropriate entity instance.
An entity is typically not shared between BCs. You may have another BC in play. You should have one BC that is the system of record for the entity. All other BCs should be downstream from it and contain only the identity and relevant bits of data. Typically one would employ an event-driven architecture to notify dependent systems of any relevant changes to the state of the entity in question.
It may also be that you are trying to split a single BC. Perhaps focus on the BC side of things as opposed to the technical/application side.
Hope that helps :)
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.
I'm using C++ (with the Qt library) to make a simple domain modeled application. I am writing my own O/R mapping classes. As this application will grow in the future I'm trying to keep a clean codebase with clearly separated layers.
The problem I am having is when and where to load aggregate roots that are referenced in an object in another module. (I am using Eric Evans' use of the word "module" here, from the DDD book.)
I currently have a simple object called Client that sits in the ClientModule module. In the PermitModule I have a Permit object. (the reality is more complex but for brevity I'll stick to those two objects, since they are the aggregate roots) The Permit object has a reference to a Client as applicant. This is my domain model.
From the bottom up, I have an Infrastructure Layer that contains O/R mapping classes and concrete implementations of Repository objects. So I would have a ClientMapper, ClientRepositoryDb, PermitMapper, and PermitRepositoryDb classes here.
Next is the Domain Layer that contains the domain model (Client and Permit classes) plus the repository interfaces ClientRepository and PermitRepository.
Above that I have an Application Layer and then a Presentation Layer but those don't matter in this example.
My question is should the relationship between Permit and Client be loaded in the PermitMapper class or in the PermitRepository class. Or is there some other way of doing it?
This goes not only for loading objects but also for saving them and removing them.
I've gone with the approach that my Mapper classes load themselves fully.
I'm not a Java developer but I wonder how Hibernate (et al) does it?