If someone asks you the meaning of a word, most of the time you don’t have an absolute meaning and end up asking for the context in which it is used. You need to know the context to get to the correct meaning. Similarly, to know your domain model right, you get to know the bounded context it is in.
Let us understand the path that leads to bounded contexts.
We started with procedural programming where execution happens linearly from the main function. The disadvantages of procedural programming are no security, difficulty to maintain, difficulty to understand, and difficulty to relate to the real world.
To overcome the above disadvantages, we moved to object-oriented programming. This is good and fixed most of the issues with procedural programming. It seems to be connected with the real world but is it for real?
Then there is the waterfall method, for a long time, to execute the project but set back with the disadvantages — no working software is produced until late during the life cycle, resulting in high amounts of risk and uncertainty, not suited to allow changes in requirements, the gaps are found very late, etc. Once the design phase is done, the Business is not involved in project execution which is high risk.
To overcome the above disadvantages, we moved to Agile methodology. Agile makes everyone (business analysts, designers, developers, and testers) involved in the project execution from beginning till end. So, all the teams need to be on the same page.
In object-oriented programming, the software seems to be connected with the real world. But it is limited to only the world of application designers. It matched with only his vision of the world. The way he sees it. It did not match with the real world of business. So, the business and analysts, designers, developers are never on the same page.
As Agile demands, everyone to be on the same page, all team components should be working in the same world. This is where the domain-driven design comes into the picture.
Domain-driven design is an approach to software development that is centered on the business domain. The domain-driven-design combines design and execution, facilitates design and development go together to create a better solution. Good design will fasten the development, while feedback coming from the development process will lead the execution in the right direction.
Everyone needs to be involved — domain experts, design experts, developers, etc. in designing the model.
The domain experts see that the model reflects the business. The developers will have a say if the design is implementable or not. Domain experts, design experts, developers, and testers use a ubiquitous language to discuss and design the model.
The model must be consistent, unified, and pure which is achieved by bounded contexts.
Why Do We Need Bounded Contexts?
Let us consider an enterprise application in the telecom domain. There will be more than 70 applications in the system. Imagine 70 applications that have to integrate successfully to run the business. It starts with a person approaching the service provider like Airtel, Jio, etc., for a new connection. The moment he approaches the service provider, he will be considered as a Lead. He is not the customer yet. If he shows interest in any plan, he will be considered as an opportunity. His details will go to application verification systems.
If everything is fine, the helpline guy or the sales guy will call and confirm his plan. Once he confirms a plan, he will be provisioned into the system. Then he becomes a customer. His account will be created in a profile application. Note that the same person is identified as lead, opportunity, and customer in different applications.
His details are captured in CRM — customer relationship management system, billing system, sales and marketing system, package management system, fraud management system, inventory systems, analytics tools, dealer management systems, secondary sales systems, revenue leakage tools, debt management systems, etc.
Now imagine if you want a single model — customer in this enterprise application. The leads and opportunities system will be interested in details like what is his existing service provider, through which channel did he get to know about us, etc. Profiling and the account creation systems will be interested in other details like name, address, age, profession, etc. The CRM system might be interested if there are any previous service tickets raised by the person. The sales and marketing team will be interested in his profile and usage details to get an idea of what packages could be recommended to him down the line. The billing system will be focused on the billing address and payment mode, etc. Similarly, the fraud management system, inventory systems, analytics tools, etc., will be interested in other details.
Imagine how confusing your model will be if it includes all these details. The address required for the billing application is the billing address. For the profiling system or CRM application, it will be the current address and permanent address. If the same model is used across the system, at some point in time, the billing team could feel that naming the address field as billing address is more appropriate than the current address and rename the current address field to the billing address. The model integrity is compromised which in turn breaks the system.
So, when the billing team says address, it might be billing address and when the CRM team says address it might be mailing address. The CRM team is not aware of the billing address and the billing team might not be aware of the other addresses. If these two teams discuss with each other the model you could guess the confusion it creates because of the conceptual differences.
Even if both the addresses are saved as different attributes, the billing address will be redundant and irrelevant to profiling and other applications.
The same person is a lead in leads application and opportunity in the opportunities application. He is a customer in the provisions and accounting systems. In case he did not pay the bills, he will be a defaulter in another system. If you observe, the details of the same person are interpreted differently in different applications based on the context. This is where the bounded contexts come into the picture.
The sales team cannot go to the leads/opportunities team and ask for the customer details because their model is not supposed to have customers but instead have leads /opportunities. They will understand only if you ask for the leads or opportunities details.
To get rid of these, you need to define the boundaries of your model and confine it to a context. Otherwise, there will be a lot of confusion and chaos that creeps into your system and makes the model unmanageable and impure.
You might be wondering what a model is. Don’t confuse the model with the class in object-oriented programming. The model in a domain-driven designed project is your solution to the problem.
The model usually represents a business solution in its own language and concepts. In a complex enterprise application, it might be a simplification of a bigger picture so that the important concepts are focused and not so important details are ignored.
This means your model should be focused on the knowledge around a specific problem that is simplified and structured to provide a solution. There are patterns to design a model.
Here are the building blocks of a model-driven design.
- Layered Architecture
- Value Objects
For the time being understood that the model represents a solution to the problem. The customer mentioned in the above section will be an entity in the domain model.
What Is Bounded Context?
A bounded context is a logical framework in which the model evolves. It gives your model the boundaries and determines the kinds of translations permitted between the boundaries.
A large system needs to have multiple models. Each model needs to be consistent and pure. It should have the data related to its bounded context only and ignore the data related to other contexts. For example, every application mentioned in the above example like leads, profiling, CRM, billing has different models. They might be connecting to the same database but still have different models. Billing-related data is never included in the CRM model or vice versa.
Suppose there is a reporting system that needs to report the billing details of a customer. The reporting system needs two additional fields to be added to the customer entity in the billing model. There will be a normal tendency to add these fields to the customer entity in the billing model and use the same in reporting model. This violates the rule that the billing model should consist only of the data related to its context but not the data related to the reports model. So, the reporting team is not allowed to tweak the customer entity in the billing model. The billing model bounded context does not allow this.
The boundary or the logical frame which helps the model to maintain its integrity is called bounded context.
Here is a picture representing bounded contexts providing logical frames to the different models. The integration of all these models provides the required solution. This is achieved by the translation/context maps as shown in the below diagram:
The boundaries could be set based on:
- Team organization — a model should be small enough to be assigned to one team.
- Specific parts of the application.
- The physical location of the codebase.
- Database schema.
A Bounded Context clearly marks the applicability of a model in an application and how it relates with other contexts so that domain experts, designers, developers, and testers have a common understanding of the model and its applicability. Do not bother about its applicability in other contexts. Other contexts have their own models with different terminologies with their own concepts and rules.
Having an explicit boundary preserves the model integrity and maintains the consistency of the model keeping it unified and pure.