Boundaries of the limiting context

Boundaries are determined by the bounding context, which is of extraordinary significance in domain-driven design. For generic languages, the bounding context is the boundary of the language, and for domain models, the bounding context is the boundary of the model, both of which correspond to the definition of the Problem Space. For the architecture of the system, the bounding contexts also define the application boundaries and technical boundaries, which in turn help us determine the solution for the entire system and each bounding context. It can be said that the limiting context is an important bridge between the problem space and the solution space.

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。

Logical boundaries

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.

  • Namespace level: Logical boundaries Defined only by namespaces, But all the bounding contexts are actually in the same module, After compilation they all belong to the sameJar packet。
  • Module level: are logically separated in namespace, while different bounding contexts belong to different modules of the same project and generate their own Jar packages after compilation. If there are dependencies between the bounding contexts, the jars are loaded into the same Java virtual machine at runtime at the same time. The so-called "modules" can also be created in Java code as Jigsaw modules.

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.

Physical boundaries

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.

Database sharing

(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.

  • Coupling: although the business upper bound context is decoupled, there is still strong coupling at the database level
  • horizontal telescoping: Application services deployed on the application server can be based on Boundaries of the limiting context Separate horizontal expansion, But it is not possible at the database level

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:

  • A bounding context is missing, and the shared table corresponds to a service that is reused: when a buyer queries an item, the item service queries the current price in the price table, and when an order is submitted, the order service also queries the price in the price table to calculate the current order total; the reason for sharing price data is that we are missing a price context, and this unnecessary data sharing can be undone by introducing a price service.
  • There is a problem with the assignment of responsibilities; the responsibility of manipulating the shared table should be assigned to an existing service: both the opinion service and the crisis service need to get the template data from the mail template table and then call the mail service to combine the contents of the templates to send emails; in fact, the responsibility of getting the template data from the mail template table should be assigned to an existing mail service.
  • Shared tables correspond to two different concepts of bounding contexts: Both the warehouse context and the order context need access to the shared product table, But in reality the two contexts require completely different product information, should follow Boundaries of the limiting context Build separate tables for products。

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.

1、These features of Python are simply awesome
2、Charging like this is dangerous and can steal all the information from your phone in minutes
3、rubber tree
4、WeChat applet practice serverside interface restful configuration
5、Millions of talents into Hainan Hainan Institute of Big Data and Artificial Intelligence officially launched

    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送