This article can be interpreted as a summary or what i learnt about defining an application's microservcie architecture from Chris Richardson's Microservices Patterns book. I'd highly recommend this book to every software engineer who's interested in understanding microservices at much deeper as well as broader level. Therefore, I'd start the article with an amazing and my favorite sentence from the book
"Like much of the software development, defining an architecture is more art than science"
An application have it's own set of requirements that it must fulfil, so the first step in defining it's architecture is identifying the key requests. To simplify the description of these requests, we'd use System Operations and they will be derived from the requirements. A system operation is either a
The next step in this process is to utilize these system operations to determine the decomposition into services. There are 2 strategies here which can be applied here
System Operations are derived from application's requirements using a two-step process. The first step is to create a high-level domain model and the next is to define the system operations in terms of domain model. We'll try to approach this using this AddToCart user scenario as an example -
"As a Customer, I want to select a car from the menu and add it to the shopping cart "
The domain model is primarily derived from the nouns of functional requirements, and the system operations are derived mostly from the verbs.
Creating a high-level domain model
The Purpose of sketching a high-level domain model is to define the vocabulary for describing the behavior of system operations. It is created using standard techniques such as analyzing the nouns in the stories and scenarios.
The nouns in the AddToCart scenario hints at existence of various classes like Customer, Car, Menu, Order. We can define responsibilities of these classes as well :
Defining System Operations
Once our high-level domain model is ready, we should move on to identifying the requests that the application must handle. A good starting point for that would be to analyze verbs in the AddToCart user scenario. And it clearly suggests that the system must provide a 'addToCart' (command) and 'showAvailableCars' (query) operation.
A command has a specification that defines it's parameters, return value, pre-conditions and post-conditions in terms of domain model classes. Let's take a look at addToCart() system operation :
Operation - addToCart (customerId, Car)
Returns - shoppingCartId
Preconditions -
- The customer exists and is eligible for shopping
- The car must be in stock
Postconditions -
- Shopping Cart's total amount is updated
- Shopping Cart's total items are updated
Most of the time, commands are more architecturally relevant, but sometimes queries are also important. Here, showAvailableCars is also architecturally significant, It's a complex query involving filters like availability, geolocation and has to provide data in a sorted order of popularity, pricing etc. Hence, this makes it performance-critical as it will be executed each time a customer wants to add items in their shopping cart.
Now that we've defined our system operations, let's move onto identifying application's services. Let's look at the first strategy, which defines services corresponding to business capabilities.
An organization's business capabilities can be identifies by analyzing the organization's purpose, structure and business processes. Each business capabilities can be thought of as a service, which consists of various components, including inputs, outputs and SLAs (Service Level Agreements). For example, The business capabilities for an online store include :
Once you've defined the business capabilities, you then define a service for each capability or group of related capabilities. A key benefit of organizing services around capabilities is that they're stable, thus making the architecture stable as well. Now, even when the aspects of business changes, only the individual components evolve, but the architecture remains unchanged.
A domain model captures knowledge about a domain in a form that can be used to solve problems within that domain. It defines the vocabulary used within the team, and is closely mirrored in the design and implementation of the application. DDD (Domain Driven Design) refers to the application’s problem space - the business - as the domain. A domain is consists of multiple subdomains. Each subdomain corresponds to a different part of the business. For example, in a food ordering app, the subdomains can be
DDD calls the scope of a domain model a bounded context. A bounded context is a service or possibly a set of services. We can create a microservice architecture by applying DDD and defining a service for each subdomain. The DDD concept of subdomains and bounded contexts maps nicely to services within a microservice architecture.
Copyright © Deepanshu Rathi