Domain-driven design (DDD) divides a complex domain up into multiple bounded contexts, and maps out the relationships between them. From these bounded contexts, a single one is selected to become the bubble, and its relationships between the other bounded contexts are analysed in detail. These relationships become the basis for the anti-corruption layer where any conceptual objects from the legacy model are translated before being utilised by the selected bounded context.
Before you start
An application domain contains many subdomains which represent its inner workings. This is especially true for many legacy systems, where the software has simply grown over time to address changing requirements. Sometimes, a legacy system may be made up of a series of smaller applications with potentially complex relationships between them. Each of these applications could be considered subdomains of the whole and, in their own right, domains with their own subdomains.
The existence of these domains and subdomains allows for a measured approach to migration that addresses each component or subdomain in turn, without corrupting the new system with existing concepts and ideas. Before starting this activity, a good understanding of the existing systems domain is important.
Level of difficulty
60 minutes per bubble context, assuming the complexity of its iterations to the system as a whole does not go beyond three distinct connections.
- Business analyst
- Squad lead
- Web engineer
- Test engineer
- Break your complex domain down into a series of bounded contexts with the relationships between them mapped out. For this, we make use of something called concept mapping. For more information see <div class="embed-container youtube">
- From these, select the context you will create your bubble from. It is ideal that this is not too complex, but still provides enough intricacy that there is value in migrating it.
- Now that we have selected our bounded context, we can begin to create our new model. Ensure that this model is built based on the requirements of the new system and not on the legacy system. This is your opportunity to improve the application and remove redundancies.
- Have a look at the relationships between your selected bounded context and the others in your domain. List these in detail, taking special note of the conceptual objects involved (i.e entities, services, data structures, protocols etc).
- Given this list, explore how they would be represented within the bubble context and update your model accordingly. Write this down.
With these details, we can now start building out what is required by our anti-corruption layer. This will include any services, translators and adapters. Ask the questions:
- What data do we need?
- How does this data differ between the two contexts.
Once we have built out our anti-corruption layer and bubble context, we are ready to put them into action.
A highly important part of migrating a legacy application is ensuring that the new application does not end up inheriting the technical debt apparent within the existing legacy model. For a successful migration, it is equally important that any risks associated with the project are minimised, and the overall exposure is reduced to maximise success. To achieve this, we use two domain-driven design concepts. The bubble context and the anti-corruption layer.
To have a bubble context is to have established a small bounded context through the use of an anti-corruption layer. This small bounded context reduces the risk and complexity when migrating large legacy systems through the breaking down of the problem into smaller manageable pieces. The anti-corruption layer protects this smaller piece of the larger system from the corruption from the old legacy system, and allows it to be developed independently.
Through independence, many of the old concepts or models that may exist in the legacy system can be adopted, or removed completely, as required for the new system, without any existing dependencies being broken.
While being developed independently and in isolation, the newly migrated system that exists within our bubble can still interact with the legacy system, and as such can still be integrated as a useful part of the whole while still maintaining its own model.
This is achieved through the use of the anti-corruption layer. The anti-corruption layer provides a series of services, facades, adapters and translators to transform the data from the legacy context into the new migrated context contained within our bubble, and often vice versa maintaining the connection and the integrity of both systems. This separation of the two contexts prevents either context from morphing to mirror the other and thus allowing the new model to remain strong.
An anti-corruption layer can be utilised to bridge multiple bounded contexts with the same benefits found when using the single context contained within our bubbles. This assists in the migration and integration of multiple parts of the system.
Although the purpose of the bubble context is to maintain separation from the legacy system, bubbles can pop. When this occurs, the context maintained within the bubble can be integrated back into the existing system seamlessly through the use of our anti-corruption layer.
Once an application has started to be broken down into its component contexts, the concept of microservices starts to make more sense. The reduction in risk can be maintained through the usage of a microservice architecture.
As each bounded context of the system is transformed into a bubble context, they can be integrated back into the system as a microservice.
For more detail on the how the bubble context and anti-corruption can be useful tools in legacy migration, watch <div class="embed-container youtube"> <iframe src="https://www.youtube.com/embed/OTF2Y6TLTG0" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen title="YouTube video"> </iframe> </div> on domain-driven design strategies for dealing with legacy systems.