10 Commandments of Microservice Decomposition
In this article, I will try to cover the purposes of terms used while decomposing microservices and try to fit them under one umbrella concept.
Join the DZone community and get the full member experience.Join For Free
While we are talking about microservices, we talk a lot about Domain-Driven Design, Event-Driven Architecture, Core Domain, Subdomain, Bounded Context, Anti-corruption Layer, etc.
Whether you are working in a Brownfield project or a Greenfield project, if your organization wants to adopt microservices, (assuming your organization has a compelling reason for adopting microservices, as it is not a free lunch), then you need to understand the above terms in detail to properly decompose your business domain logic (Business Space) and map it with microservices architecture (Code Space), so you can gain the benefits of microservice traits.
In this article, I will try to cover the purposes of the above-mentioned terms while decomposing microservices and try to fit them under one umbrella concept.
To understand each term from the root, it must be one or more than one article. Having said that, I will summarize them in this article and give you some pointers while you are applying the microservice decomposition strategy in your organization.
The 10 Commandments of Microservice Decomposition
1. View Your Business Domain in Terms of Bounded Context and Ubiquitous Language:
Before taking any step on decomposition, the first thing first is to reduce the gap between product owners and developers, product owners may not understand technical terms, and the technical team may not understand the importance of a term in terms of business and how businesses interpret them. It is like one Portuguese talking with one American with their own native languages: no one understood the conversation, so to bridge the gap we need to take the below steps:
Gather in front of a drawing board start a discussion with product owners: 'what is the objective of the business?;' 'what are the actors in a particular feature?;' 'what are the terms they used while defining the feature?'
On every step ask more questions until you figure out what the conflicting terms are, like an Order Context Customer is different than an Infrastructure Support Context Customer.
Once you understand the conflicting terms and clubbed the related feature, draw a context so that in each context every domain entity name is clear.
Define a ubiquitous language for each context so the business team and tech team can sync using a common language when they communicate.
Start with a coarse-grained bounded context. If later it has a compelling reason to divide, then divide the bounded context. I would recommend not to do that if there is a business reason.
2. Identify the Core Domain and Apply Innovative Idea:
The core domain is the domain that brings the revenue to your business. Say for online shopping, shopping cart module is the core domain which gives the platform to Buy and Sell (B2C) opportunity from business to consumers. Understand your core module is and think about how you can improve that module which your competitor does not have. Any automation or innovations will add advantage and boost your revenue, so pay attention; do R&D and invest money in the core domain to stay ahead of the competition.
3. Do Cost Optimization on Generic Domains:
Generic Domains are such domain which is common to every business in that niche, and a different Third-party already provides the solution and commercializes the market. Like your notification module or ad campaign module for your business, it is the best strategy not to spend money on an in-house project to create this module to reinvent the wheel, unless you have some compelling reason. Preferably, adopt the third-party solution for the cheap price.
4. Think on Support Domains:
The core domain needs the support domain's help to enrich itself, and in some cases, the support domain can lead the revenue and can be possible core domains in the future. So it is important to think and take decisions to invest in the support domain so that it can generate revenue. Like in a Shopping Cart domain, inventory management is the support domain, but it is important to invest money to expand inventory locations to cut down the shipping cost. It is also important to invest in algorithms which can identify the nearest inventory location for a customer order to reduce shipping cost.
5. Introduce Anti-Corruption Layer:
The anti-corruption layer is an integral part of microservice design it protects microservices from outer world malformation. In real-time, a legacy project will encounter such an old system that builds on the mainframe, or any other language. While you are doing decommission, they are the important source of microservice input data and live side-by-side with microservices architecture. You can not decompose that system for various reasons.
So it is a good idea to create a facade between legacy and microservice communication, rather than directly consume data from legacy and create coupling on microservice and legacy architecture.
Also think on the generic domain as they are adopting third party library so rather than directly consume/publish the data according to their contract introduce an anti-corruption layer which insulated the microservices from outer world contract API, the port and hub pattern, so rather than driven by their contract we create our contract and ACL (Anti-corruption Layer) to act as a translator between microservice and third party contact. It helps you to adopt any third-party library in the future.
6. Identify the Data Communication Patterns:
Once you decompose the microservices based on the features, and your core services encapsulated their own database/persistence layer, (database per service), the next important things to understand, to complete a feature, how your UI views/components will communicate with each other, is it a sequential flow? At a one-shot, your user needs to complete the whole feature, or it can be asynchronous where the user can do a partial functionality and create an intermediate state, another system takes action on the intermediate state and calls back or notify the user to resume the action.
7. Introducing Event-Driven Architecture (EDA):
In a real-time application, your business cases having complex workflows and many branches on the workflows based on the state of the data, based on the state change. Workflow took a different strategy, so if you think to expose it all by Rest API, you will see that it creates a chatty network. Each microservice is coupled with others and it creates spaghetti code and distributed ball of muds.
So somehow we need a clean architecture where each microservices can operate independently without creating coupling, here event-driven architectures play a vital role, each event is wrapping a change of a state, and the microservices are followed pub/sub model so one microservice produces it state change and wrap the necessary data in a form of event other microservices listens to that events and can take the strategy based on the data wrapped in the event. As events are immutable it also holds the history of an entity or aggregator so if you are adopting an event store and event storming you can generate any statistics and report from the events.
8. Make API Contract Clean and Concise:
In microservices, you need to publish API so it will act as a contract, so while you are publishing API make sure your API does not publish an internal state. Think about the encapsulation, and think about the network call; publish API is such a way that other services can get enough information to carry on their flow, but they should not come back multiple times for getting derivative information. Also think about the events, which events you should publish, and which must remain inside. Maybe you can publish one coarse-grained event rather than publish small internal events.
Example: Say internally, you have Address Change Event and Personal Info Change Event. Rather than publish both in API contract, publish a coarse-grained event called CustomerUpdateEvent.
9. Merge Related Microservices to a Bigger Service:
After decomposing, you can experience a few microservices always changing together when a feature needs to be added or updated. Then you know you decomposed it in the wrong way; they must not be segregated to a small service, they are part of the same logical unit. So it is wise to merge them into a single service; it will reduce unnecessary coupling and network calls.
10. Introduce Supporting Tool for Seamless Development:
Microservices is no free lunch. If you adopt microservices, first things first, be ready to expense on the supporting software as microservice is distributed. We adopt it for scaling resiliency and high availability and reduce time to market. It is distributed and works over the network, so failure is inevitable and you need to catch the failure at the earliest without spending on infrastructure it is not possible.
If you spend well, then the microservice allows you to buy out different options and help your organization to grow further.
So spend on CI/CD pipeline, adopt cloud infrastructure, use tracing tool, use log aggregator to search logs, use chaos tools for checking how you are prepared for failure, etc.
The above points are necessary while you are decomposing microservices. I will write an article on each topic on how they play a pivotal role in adopting a microservices architecture. Also, I'd like to hear from you more about the challenges you faced while decomposing to microservices.
Published at DZone with permission of Shamik Mitra, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.