Listen to this story
Subscribe to my channel https://t.me/zufarexplained
The writer is smart, but don't just like, take their word for it. #DoYourOwnResearch
Way back in August 2008, Netflix had a significant outage because of a major database corruption which prevented them from shipping DVDs to customers for three days. Following this, they decided to move away from a single point of failure–that could only scale vertically–and move to components that could scale horizontally and are highly available [1].
I am excited to share a series of articles on Microservice Architecture Patterns. In this series, we will explore various categories of microservice architecture patterns, including decomposition, integration, database, observability, cross-cutting concern microservice architecture patterns, and others.
In this first article, we will focus on decomposition patterns. These patterns help to break down a monolithic application into smaller, more manageable microservices. In detail, we will discuss three decomposition patterns: microservices decomposition by business capability, microservices decomposition by subdomain, and microservices decomposition by transaction. By the end of this article, you will better understand how to use these patterns to design and implement microservice architecture in your projects.
Microservices are an architectural and organizational approach to software development where software is composed of small independent services that communicate over well-defined APIs [2]. Basically, microservice architecture approach has become popular in building software systems, especially in modern web applications.
Challenges Ahead
While microservices offer many benefits, they also come with some challenges:
To address these challenges, software developers and architects have developed a variety of software architectural patterns that can help to overcome microservice architecture drawbacks and disadvantages.
Software Architectural Patterns
Using patterns, you can avoid reinventing the wheel and leverage proven solutions to common problems when designing and building software systems. In the context of microservice architecture, patterns can help address some of the challenges that arise when dealing with many independent services and can reduce complexity, increase reliability, and improve the system's maintainability.
As mentioned above, there are many different categories of microservice architecture patterns, but without one category of patterns, there would be no microservice architecture. This category is microservices decomposition patterns, which enables splitting the application into a set of loosely coupled services. There are three primary decomposition approaches, and we can learn all of them further. Let's start!
This approach is based on business capability decomposition, which aims to create microservices aligned with the business needs and can be developed and maintained independently. Business capabilities are the specific functions or processes that an organization performs to deliver value to its customers [3]. It is a high-level concept that describes what a business does rather than how it does it. For example, a banking application might have business capabilities for account management, transaction processing, and loan origination. Each of these capabilities could be supported by a separate microservice.
Here are some situations in which business capability decomposition may be a good fit:
Let's consider a hypothetical healthcare platform that provides various services such as patient management, appointment scheduling, electronic medical records (EMR) management, billing and payment processing, and telemedicine services. To decompose these business capabilities into microservices, we can assign one distinct business capability and its data to a separate microservice, which can be developed, deployed, and scaled independently.
Here is an architectural diagram that illustrates this decomposition.
Picture 1. Transition of the healthcare platform to the set of microservices decomposed by business capability
In Picture 1, we can see how the healthcare platform can be decomposed into microservices based on business capabilities:
Patient Management: This microservice manages patient records, such as patient demographics, medical history, and insurance information.
Appointment Scheduling: This microservice is responsible for scheduling patient appointments, sending patient reminders, and managing the appointment booking process.
Electronic Medical Records (EMR) Management: This microservice manages patient medical records electronically, including lab results, imaging studies, and other medical data.
Billing and Payment Processing: This microservice generates patient invoices, processes payments, and manages insurance claims.
Telemedicine: This microservice provides patients with remote consultations and telemedicine services, allowing them to consult with doctors remotely.
We can achieve better scalability, flexibility, and maintainability by decomposing the healthcare platform into microservices based on business capabilities. For example, we can scale up the Telemedicine microservice during a pandemic or other situations where remote consultations are in high demand without affecting the performance of other services.
One popular approach to decomposing microservices is through transaction decomposition, where the system is designed such that each particular transaction belongs to a separate microservice. A transaction, in this context, refers to a series of operations performed between components of the system as a unit of work to achieve a particular business goal.
In this pattern, the components that participate in a transaction are grouped together as part of the same microservice. This grouping helps to avoid problems with two-phase commit and reduces latency issues that may arise in a distributed system. By adopting this approach, organizations can achieve a more efficient and scalable microservice architecture that is better suited to their specific business needs [6].
This pattern can be reasonable in the following scenarios:
Let's consider an e-commerce application that allows customers to purchase products online. To implement this application using microservice architecture, we could use the transaction decomposition pattern to break down the system into smaller, more manageable microservices that each handle a particular transaction.
Here is an architectural diagram that illustrates this decomposition.
Picture 2. Transition of the e-commerce platform to the set of microservices decomposed by transaction
In Picture 2, we can see how the e-commerce platform can be decomposed by transaction into microservices that could be part of this system:
Shipping microservice: This microservice would handle the transaction that involves shipping the order to the customer. It would handle tasks such as generating shipping labels, updating tracking information, and communicating with the carrier.
Product catalog microservice: This microservice would handle the transaction that displays product information to the customer. It would handle tasks such as retrieving product information from a database, caching product data, and providing search and filtering functionality.
Payment processing microservice: This microservice would handle the transaction that involves processing the customer's payment. It would handle tasks such as verifying the customer's payment information, communicating with the payment gateway, and updating the order status.
Order management microservice: This microservice would handle the transaction that involves creating and processing an order. It would handle tasks such as validating the customer's payment information, updating inventory, and sending a confirmation email to the customer.
By breaking down the system into these smaller microservices, we can achieve a more scalable, fault-tolerant, and efficient system that can better handle the demands of a high-traffic e-commerce website. Each microservice is responsible for a specific transaction, which helps to minimize complexity and improve performance.
Microservice decomposition by subdomain is a process of breaking down a monolithic system into smaller, independent microservices based on the corresponding subdomains defined by Domain-Driven Design (DDD). DDD refers to the application's problem space - the business - as the domain, which is comprised of multiple subdomains [8]. The scope of each subdomain's model is called a bounded context, around which microservices are developed. This pattern is suitable for monolithic systems that have clear boundaries between subdomains and allows the repackaging of existing modules as microservices without extensive code rewriting. By breaking down the monolithic system into microservices based on subdomains, each microservice has its own model, which enables greater agility, scalability, and maintainability.
Microservices decomposition by subdomain is a software design pattern that is well-suited for applications that have complex business logic and are expected to evolve over time. This approach to software design enables developers to break down a large, monolithic application into smaller, independent services that are focused on specific areas of business functionality.
Here are some scenarios where this pattern is well-suited:
Let's consider an insurance monolith application that allows clients to purchase insurance online. To implement this application using microservice architecture, we could use the subdomain decomposition pattern to break down the system into smaller, more manageable microservices that each belong to a particular subdomain. Here is an architectural diagram that illustrates this decomposition [10].
Picture 3. Transition of the insurance monolith to the set of microservices decomposed by subdomain
In Picture 3, we can see how the insurance monolith application was decomposed by business capabilities into four services: sales, customer, compliance, and marketing. Then the sales service was further divided into purchasing and claims subdomains, while the marketing subdomain was divided into campaigns, analytics, and reports subdomains.
Here's a brief overview of microservices that were created in each subdomain:
Purchasing service: handles the purchase of insurance policies
Claims service: handles the processing of insurance claims
Customer service: manages customer information and interactions
Compliance service: ensures regulatory compliance and manages risk
Campaigns service: manages marketing campaigns
Analytics service: tracks and analyzes marketing data
Reports service: generates reports on marketing performance
By decomposing this monolith into microservices based on subdomains, the company was able to improve its agility, scalability, and time to market. They could independently develop, test, and deploy each microservice, allowing them to innovate faster and respond quickly to changing market demands. Additionally, they improved the reliability and availability of their services, as failures in one microservice did not affect the entire system.
In conclusion, microservice architecture is a powerful approach to building modern distributed systems, and decomposition patterns provide valuable strategies for breaking down a monolithic application into smaller, more manageable microservices. By using patterns such as decomposition by transaction, decomposition by subdomain, or decomposition by business capability, teams can create a more flexible, scalable, and maintainable architecture. However, it is important to note that each pattern has its advantages and disadvantages, and choosing the wrong strategy can lead to significant challenges and issues. Therefore, readers should carefully consider the specifics of their project and choose the correct pattern that best suits their needs to ensure a successful implementation of microservices.
Zufar Sunagatov is an experienced senior software engineer passionate about designing modern software systems. He strongly advocates microservice architecture and has worked extensively with complex distributed systems using various design patterns in big e-commerce, fintech, and insurance companies. Zufar is an active member of the software development community and regularly shares his knowledge and expertise on his Telegram channel ZufarExplainedIT and LinkedIn where he explains algorithm and system design task solutions and approaches that have been well-received by the community.