Microservices, bounded context, cohesion. What do they have in common?
We live in a decade where the industry has a general consensus on how to scale an organization. We know that microservices help us work together with hundreds or thousands of other software engineers, we know autonomy is a key factor and DDD is fundamental to communicate clarity with other teams and the business.
Yet, it seems that a lot of companies are struggling with how to split the monolith within different services. In my experience most of the decisions on the monolith splitting is by data model. In an ecommerce for example, you may be willing to start by the product service and move all the product information there. But if you look closer at your product data model, probably you will see information not directly related to product information.
An ecommerce has information on the product that is needed to successfully send the product to the customer. An example of it is the box characteristics needed to deliver the product like size, format or material. Depending on the box associated with the product, different shipping options will be available.
“So, what is that thing you call cohesion?”
You probably hear the concept coupling. Coupling is a measure that defines the level of inter-dependability between modules or components. Normally, low coupling is a great thing and high coupling is a bad thing.
In the example above, using Microservices you would probably have one service for the product and another for the shipping. If you choose to have the box information on the product service, then the shipping service would need to get this information from the product service in order to do the shipping logic to find available shipping options, either by having the shipping service calling product service or by having a layer of orchestration between them.
At first sight it may not seem very important. Tomayto, tomahto, you may say. So lets try and add more logic into the shipping service.
As a delivery operations manager, I want to categorize products, so that I can choose which delivery options to show to the customer
Let’s imagine our ecommerce has some dangerous products that cannot be shipped by air. This means that the shipping service now needs to change in order to give to the customer the shipping options with these rules in place.
For that we will want to categorize the product in order to add logic on the shipping service to select the options that are allowed.
As you may guess, we will change the product service to add the new categorization feature, change the API to include that information and change the shipping service to have the logic to select the right shipping options. We may use the shipping service to get the product or we may use orchestration to send this categorization to the shipping service, as we said before.
“In a good designed microservice architecture the dependencies between services are minimized.” - https://specify.io/concepts/microservices
This may not be the best design for our architecture. Shipping and product have a high coupling, but also a low cohesion. The necessary data for the shipping service to work correctly is on the product service.
You can measure cohesion by the number of services you need to change if you add a new feature.
That is one of the reasons some companies are struggling with microservices and the cost of changing anything in the system is so high. One simple change and we need to change at least two services.
But it’s related to the product. It’s product information!!!
Yes, it’s related to the product. But the functionality is entirely related to the shipping. If we did have the things we need from product on the shipping service it would be easier to change our software, because we would need to change only the shipping service in order to deliver the feature to production. Less components changing, less chances for things to go wrong, the easier is the deploy, the easier and simpler are the tests to validate the feature and the simpler the architecture is for the software engineers.
Bounded context tries to define boundaries of our complex domain into business context. Bounded contexts are important because they allow us to define an ubiquitous language that is shared and valid within a boundary.
The meaning of a product for the shipping bounded context is not the same as for the product bounded context.
The domain expert of the product may not understand anything about the shipping rules or what box to use to deliver the product to the customer. However, this information is part of day to day activity of the delivery domain expert and he may even be able to help you to automate part of the system.
So let’s go back a little. Now that we’ve heard about bounded context you may be asking yourself what is the difference between this and what we did with the product service and shipping service. To be honest, I don’t see much of a difference.
Using bounded context is a great way to keep your system with high cohesion.
How to have consistency between shipping and product?
Our industry is still very stuck with transactions and consistency in the system. Consistency is important, I would not say otherwise, but we may only need eventual consistency for our system.
One of the most frequently asked questions I get when trying to implement this idea of splitting the monolith into services is how to keep consistency between shipping and product? Or, in other words, how to be sure I will only have products in the shipping service that exist in the product service?
For that let’s get into a rule for a good microservices architecture: choreography should be preferred over orchestration. The person that will categorize the product for the shipping may be different than the person that will categorize the product for the catalog information. It will probably not happen at the same time either.
That means that you will be able to subscribe the events of the product service. “ProductCreated” and “ProductDeleted” to have the consistency you need.
Time travel to 2030
Time goes by and internet is not the best thing in the world. Customers now don’t like ecommerce. Our ecommerce isn’t going well, we will close the site and focus on our stores’ operations. We will not need the shipping anymore.
Wouldn’t it be amazing if we could remove the shipping service and not have any data related to the shipping logic remaining?