Boundaries of the limiting context
or so, Boundaries defined by the limiting context, actually Logical boundaries, orPhysical boundaries? It's not conclusive., Different decisions need to be made based on different scenarios。
When logically decomposing the domain according to the business, division and union are two contradictory yet unified concepts. Combining is the goal, dividing is a means of reducing complexity. The split is actually for a better fit. With business decomposition, each decomposed bounding context becomes smaller in size and therefore easier to understand and control. Since this decomposition is considered in terms of business relevance, it allows the domain to be more segmented and the business analyst or domain expert can then be required to master only the more segmented areas of specialization.
In terms of the code model of the system (Code Model), the so-called Logical boundaries There are two forms of presentation. Using Java as an example, it is summarized as follows.
Treating boundaries that qualify the context as logical boundaries is the most common and simplest form. On the one hand the separation of logic ensures a clear structure of the system code, and on the other hand it makes collaboration between bounding contexts easier and more efficient. Physically, the bounding contexts are actually seamlessly integrated with each other in terms of communication, and the domain models to be reused are directly accessible and instantiated to the model classes. The following are the logical boundaries of the international tax filing system (Java).
However, as the saying goes The easier it is to reuse, the easier it is to create coupling . When writing code, we need to adhere to this invisible logical boundary, always taking care not to overstep it, and determining the respective interfaces that the bounding contexts expose to the public to avoid dependencies on specific implementations.
A system architecture that uses logical boundaries to delineate the bounding context is a monolithic (Monolithic) architecture , all the bounding contexts are deployed in the same process, so horizontal scaling cannot be performed for a particular bounding context. When a replacement or upgrade of the implementation of the bounding context is required, it affects the entire system. Even if we hold the logical boundaries, this coupling still exists, leading to development in various bounding contexts affecting each other and the cost of coordination between teams.
Logical boundaries bad guys, exactlyPhysical boundaries good friends; conversely,Physical boundaries bad guys, equal Logical boundaries good friends。 When we put the Boundaries of the limiting context define asPhysical boundaries time, Each bounding context then becomes a fine-grained microservice。
Here, we need further clarification on the concept of "bounded context" proposed by Eric Evans. Is the bounding context just a boundary delineation for the domain model, or is it a vertical delineation of the entire architecture (including the infrastructure layer as well as the external resources that need to be used)? As the previous quote from Eric Evans' point of view clearly states in his book Domain Driven Design, "Set the boundaries of the model based on the organization of the team, the usage of the various parts of the software system, and the physical representation (code and database schema, etc.). "Clearly, the limiting context does not only act at the domain and application layers. It is a key element of architectural design rather than just domain design.
If we take Boundaries of the limiting context consider to bePhysical boundaries, then services within the boundary can be guaranteed、 Infrastructure and even storage resources、 Integrity of other external resources such as middleware, Resulting in autonomous services。 Communication between bounding contexts is done only in a bounded way and in a bounded communication protocol and data format, beyond, There's nothing to share with each other, This architecture is called Zero-Share Architecture . This architecture is expressed in terms of each bounding context having its own code base, data store, and development team, and the technology stack and language platform chosen for each bounding context can also be different. When each bounding context is physically isolated, developers in one bounding context cannot call methods in another bounding context or store data in a shared structure, which avoids coupling due to sharing. The following diagram shows the architecture of the crisis analysis system.
The physically separated confining context becomes small and specialized, allowing us to nicely arrange small teams that follow 2PTs rules to govern it. However, the complexity of this architecture should not be underestimated. Communication between bounding contexts is cross-process and we need to consider the robustness of the communication. The database is completely separated, and when data between associations is needed, it has to be accessed across the restricted context, without the benefit of the associations provided by the database itself. Since each bounding context is distributed, it is also a tricky task to ensure data consistency. The complexity of operations and monitoring increases dramatically when the entire system is broken down into bounded contexts that can be deployed independently.
(located) at Logical boundaries harmonyPhysical boundaries interlocutory, A compromise also exists。 When considering the delimitation of the bounding context, Consider the code model separately from the database model, Then there may be a separation in the code, Instead, a form of data sharing exists at the database level, i.e. multiple bounding contexts sharing the same database。
Because there is no subrepository, the ACID of the transaction can be better guaranteed at the database level. This is perhaps the most compelling evidence of the scheme, but it can also be seen as a compromise of the "consistency" constraint.
The problem with database sharing is that the direction of change in the database can be inconsistent with the direction of change in the business. This inconsistency is reflected in two ways.
According to the microservices architecture best practices proposed by the Netflix team, one of the most important features is " Separate data storage for each microservice ". But the separation of services does not absolutely mean that data should be separated. There may not be a one-to-one mapping between the database style (Schema) and the domain model. When designing a sub-repository for data, thinking only in terms of business boundaries may lead to unnecessary cross-repository correlations because the granularity of the sub-repository is too small. Therefore, we can think of the "database sharing" model as a transitional solution, rather than designing microservices to separate data completely at the outset, but rather as an evolutionary design.
To facilitate the refactoring of sub-tables into sub-repositories in the evolutionary design, it is important from the outset to Be careful to avoid creating foreign key constraint relationships between two tables . Some relational databases may provide cascading update and delete functionality through such constraint relationships, which in turn can affect the implementation of the code. Once the foreign key constraint relationships between tables are removed due to splitting, too much code needs to be modified, which can make the evolution too costly and may even introduce hidden bugs due to some oversight.
The absence of foreign key constraint relationships may increase development costs in the present, but opens the door for future evolution. For example, in the opinion analysis system developed for a mobile phone brand, the crisis query service provides queries on identified crises, and the details of crisis handlers and crisis reporters need to be obtained through userId. The figure on the left shows a direct query through the database before the evolution, while the figure on the right cuts off this database coupling in favour of service invocation.
If the architecture is designed to Database sharing, and both services need to operate on the same data table( This table is called“ shared table”), Then a signal is sent, That is, our design may have been wrong:
Why do these three wrong designs occur? The root cause is still that we are not modeling through the business, but implicitly in the database, and thus the correct domain model is not reflected in the code, leading to coupling or sharing at the database level.