Strategic design and principles

An enterprise model is usually very large and complex. It may be distributed among different departments in an organization. Each department may have a separate leadership team, so working and designing together can create difficulty and coordination issues. In such scenarios, maintaining the integrity of the domain model is not an easy task.

In such cases, working on a unified model is not the solution and large enterprise models need to be divided into different submodels. These submodels contain the predefined accurate relationship and contract in minute detail. Each submodel has to maintain the defined contracts without any exception.

There are various principles that could be followed to maintain the integrity of the domain model, and these are listed as follows:

  • Bounded context
  • Continuous integration
  • Context map
    • Shared kernel
    • Customer-supplier
    • Conformist
    • Anticorruption layer
    • Separate ways
    • Open host service
    • Distillation

Bounded context

When you have different submodels, it is difficult to maintain the code when all submodels are combined. You need to have a small model that can be assigned to a single team. You might need to collect the related elements and group them. Context keeps and maintains the meaning of the domain term defined for its respective submodel by applying this set of conditions.

These domain terms defines the scope of the model that creates the boundaries of the context.

Bounded context seems very similar to the module that you learned about in the previous section. In fact, module is part of the bounded context that defines the logical frame where a submodel takes place and is developed. Whereas, the module organizes the elements of the domain model and is visible in design document and the code.

Now, as a designer you would have to keep each submodel well-defined and consistent. In this way you can refactor the each model independently without affecting the other submodels. This gives the software designer the flexibility to refine and improve it at any point in time.

Now look at the table reservation example. When you started designing the system, you would have seen that the guest would visit the app and would request a table reservation in a selected restaurant, date, and time. Then, there is backend system that informs the restaurant about the booking information, and similarly, the restaurant would keep their system updated with respect to table bookings, given that tables can also be booked by the restaurant themselves. So, when you look at the systems finer points, you can see two domains models:

  • The online table reservation system
  • The offline restaurant management system

Both have their own bounded context and you need to make sure that the interface between them works fine.

Continuous integration

When you are developing, the code is scattered among many teams and various technologies. This code may be organized into different modules and has applicable bounded context for respective submodels.

This sort of development may bring with it a certain level of complexity with respect to duplicate code, a code break or maybe broken-bounded context. It happens not only because of the large size of code and domain model, but also because of other factors such as changes in team members, new members or not having a well documented model to name just a few of them.

When systems are designed and developed using DDD and Agile methodologies, domain models are not designed fully before coding starts and the domain model and its elements get evolved over a period of time with continuous improvements and refinement happening over the time.

Therefore, integration continues and this is currently one of the key reasons for development today, so it plays a very important role. In continuous integration, code is merged frequently to avoid any breaks and issues with the domain model. Merged code not only gets deployed but it is also tested on a regular basis. There are various continuous integration tools available in the market that merge, build, and deploy the code at scheduled times. Organizations, these days, put more emphasis on the automation of continuous integration. Hudson, TeamCity, and Jenkins CI are a few of the popular tools available today for continuous integration. Hudson and Jenkins CI are open source tools and TeamCity is a proprietary tool.

Having a test suite attached to each build confirms the consistency and integrity of the model. A test suite defines the model from a physical point of view, whereas UML does it logically. It tells you about any error or unexpected outcome that requires a code change. It also helps to identify errors and anomalies in a domain model early.

Context map

The context map helps you to understand the overall picture of a large enterprise application. It shows how many bounded contexts are present in the enterprise model and how they are interrelated. Therefore we can say that any diagram or document that explains the bounded contexts and relationship between them is called a context map.

Context maps helps all team members, whether they are in the same team or in different team, to understand the high-level enterprise model in the form of various parts (bounded context or submodels) and relationships. This gives individuals a clearer picture about the tasks one performs and may allow him to raise any concern/question about the model's integrity:

Context map

Context map example

The context map example diagram is a sample of a context map. Here, Table1 and Table2 both appear in the Table Reservation Context and also in the Restaurant Ledger Context. The interesting thing is that Table1 and Table2 have their own respective concept in each bounded context. Here, ubiquitous language is used to name the bounded context as table reservation and restaurant ledger.

In the following section, we will explore a few patterns that can be used to define the communication between different contexts in the context map.

Shared kernel

As the name suggests, one part of the bounded context is shared with the other's bounded context. As you can see below the Restaurant entity is being shared between the Table Reservation Context and the Restaurant Ledger Context:

Shared kernel

Shared kernel

Customer-supplier

The customer-supplier pattern represents the relationship between two bounded contexts when the output of one bounded context is required for the other bounded context that is, one supplies the information to the other (known as the customer) who consumes the information.

In a real world example, a car dealer could not sell cars until the car manufacturer delivers them. Hence, in this domain-model, the car manufacturer is the supplier and the dealer is the customer. This relationship establishes a customer-supplier relationship because the output (car) of one bounded context (car-manufacturer) is required by the other bounded context (dealer).

Here, both customer and supplier teams should meet regularly to establish a contract and form the right protocol to communicate with each other.

Conformist

This pattern is similar to that of the customer and the supplier, where one needs to provide the contract and information while the other needs to use it. Here, instead of bounded context, actual teams are involved in having an upstream/downstream relationship.

Moreover, upstream teams do not provide for the needs of the downstream team because of their lack of motivation. Therefore, it is possible that the downstream team may need to plan and work on items which will never be available. To resolve such cases, either the customer team could develop their own models if the supplier provides information that is not worth enough. If the supplier provided information is really of worth or of partial worth, then the customer can use the interface or translators that can be used to consume the supplier-provided information with the customer's own models.

Anticorruption layer

The anticorruption layer remains part of a domain and it is used when a system needs data from external systems or from their own legacy systems. Here, anticorruption is the layer that interacts with external systems and uses external system data in the domain model without affecting the integrity and originality of the domain model.

For the most part, a service can be used as an anticorruption layer that may use a facade pattern with an adapter and translator to consume external domain data within the internal model. Therefore, your system would always use the service to retrieve the data. The service layer can be designed using the façade pattern. This would make sure that it would work with the domain model to provide the required data in a given format. The service could then also use the adapter and translator patterns that would make sure that whatever format and hierarchy the data is sent in, by external sources, the service would be provided in a desired format and the hierarchy would use adapters and translators.

Separate ways

When you have a large enterprise application and a domain where different domains have no common elements and it's made of large submodels that can work independently, this still works as a single application for an end user.

In such cases, a designer could create separate models that have no relationship and develop a small application on top of them. These small applications become a single application when merged together.

An employer's Intranet application that offers various small applications such as those that are HR-related, issue trackers, transport or intra-company social networks, is one such application where a designer could use the separate ways pattern.

It would be very challenging and complex to integrate applications that were developed using separate models. Therefore, you should take care before implementing this pattern.

Open host service

A translation layer is used when two submodels interact with each other. This translation layer is used when you integrate models with an external system. This works fine when you have one submodel that uses this external system. The open host service is required when this external system is being used by many submodels to remove the extra and duplicated code because then you need to write a translation layer for each submodel external system.

An open host service provides the services of an external system using a wrapper to all sub-models.

Distillation

As you know, distillation is the process of purifying liquid. Similarly, in DDD, distillation is the process that filters out the information that is not required, and keeps only the meaningful information. It helps you to identify the core domain and the essential concepts for your business domain. It helps you to filter out the generic concepts until you get the code domain concept.

Core domain should be designed, developed and implemented with the highest attention to detail, using the developers and designers, as it is crucial for the success of the whole system.

In our table reservation system example, which is not a large, or a complex domain application, it is not difficult to identify the core domain. The core domain here exists to share the real-time accurate vacant tables in the restaurants and allows the user to reserve them in a hassle free process.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset