Microservice: Everyone Makes Mistakes — Part I

Source:

Everyone makes mistakes. The wise are not people who never make mistakes, but those who forgive themselves and learn from their mistakes.” — Ajahn Brahm (theoretical physicist, author, and Buddhist monk)

Nowadays, the microservice pattern [1] is a hot topic, which has a tremendous influence on all sorts of software engineering programs and projects. Nevertheless, through the last two years, there has been a noticeable backlash against microservices [2]. For example, [3] concluded: “due to the given burdens of cost and organizational maturity, microservices will likely never reach the Adopt phase while [2] shared a testimonial from a CTO of a major company “We traded one giant pile of crap for hundreds of smaller piles.

Most of the root causes of that backlash should not be attributed to the microservice pattern but, rather, to the mistakes made during applicational and architectural design and its consequence in the implementation and operation. Such root causes can be grouped in two broad categories: (A) the mistakes applying the microservice pattern itself and (B) the neglecting of the required organizational maturity, which includes, at least: test capabilities inadequacies, DevOps capabilities insufficiencies and organizational challenges (e.g., the lack of the organization of teams around business capabilities).

The current series is focused on the mistakes applying the microservice pattern itself, providing, perhaps, for wise people, a shortcut to “learn from their mistakes” (if shortcuts exist at all). The first part is focused on the applicational design mistakes, while the second part is focused on the architectural mistakes [8].

First Mistake — The avoidance of “Right View” or business misalignment

Design the application using a set of microservices, which are well-aligned with business capabilities. Although related to organizational maturity, it is worthwhile to organize teams around such business capabilities and the services that support them.

Prefer the definition of the scope of microservices around business capabilities. Avoid technicalities in the scope definition of the microservices, e.g., the rule “10 to 100 LOC” [4] or statements shared, during a design session, with me “Each microservice should deal with a table”.

Second Mistake — The avoidance of the “Middle Way” or about the wrong scope size of the microservices

[5] argued that there is no magical rule to divide an application into microservices, or to define the optimal scope of them. Nevertheless, the literature suggests the following graph to show the influence of the number of microservices in the total cost of a software.

Cost x Number of microservices [5]

Following [5], it is reasonable that the division of one application into too many microservices (scope is too small) has a huge impact on the total cost. However, instead of a positive impact — as naively accepted — it could be a negative impact if the value in the x-axis (number of modules) is not located in the minimal-cost region. The same undesirable effect occurs when there are few microservices (scope is too big).

Indeed, the graph is a U-curve optimization, in which is not mandatory to find the perfect optimum to capture most of the value but, rather, to strive for cohesion whilst the first mistake is avoided.

Finally, recall [2]: “excessive communication between services could be a sign that services were not scoped properly and are, therefore, coupled.

Third Mistake — The avoidance of “Right Effort” or the lack of proper design

Microservices integrate through APIs, not only through synchronous transports as REST/HTTP APIs, using contracts. Therefore, the “contract-first approach” is the preferable way to design microservices.

Such emphasis on the contracts poses challenges in the designing, in particular, (1) a good understanding of the business capability allocated to a given microservice is required as well as (2) the use-cases of the consumers of such API must be considered. The latter aspect, the emphasis on the consumers, directly relates to a well-known design mistake pointed out more than 15 years ago by Gartner [6]: “the practice of “domain model dumping” is sure to be a scourge of poorly-designed APIs in the coming years”.

Domain model dumping” is the designing of the microservices exposing the richness of the domain (emphasis on the provider) without taking into account the needs of the consumers, as result, an overcomplicated API is exposed, which in turn couples unnecessarily such providers and consumers microservices. The general rule is “do not dump your domain model”.

An additional mistake in the designing of a consumer-oriented API is the mixing of master and transactional data in a microservice that supports a given business capability. For example, in an e-commerce application, a given consumer needs the order data as well as the product data in the order, one can define the contract of the order microservice to expose such aggregate (order and product data), nonetheless, such mixing of transaction data (order) and master data (product) has tremendous side-effects, e.g., unnecessary coupling of order and product microservices, possible responsiveness as well as resilience degradation of the services… A closed related mistake is the general applying of “embedding” in the contract of a microservice. Indeed, the mixing of master and transactional data often leads to “embedding.

Roughly speaking, the relationships of data in a given contract for a microservice can be designed using three techniques, namely “links”, “sideloading” and “embedding”[7]. These techniques offer different compromises between bandwidth (payload size), chatting (number of requests), decoupling and consumer-friendly. “Links” are based on the choice to provide a foreign key for data or hypermedia links, so it mainly focuses on bandwidth and decoupling. “Sideloading” prefers to decouple data and to optimize bandwidth and chatting in the expenditure of consumer-friendly (in the previous example an aggregate is defined composing product and orders without the embedding of the aggregated data). Finally, “embedding” prefers to couple data (in the previous example an order could have an explicit dependency of a product which is embedded in it) and to focus on consumer-friendly in spite of the sacrifice of bandwidth and chatting. In general, the usage of the “embedding” technique in a microservice that supports a business capability is a signal that the microservice was not designed properly and is, therefore, coupled compromising responsiveness and resilience.

Conclusion

The first part of the series “Microservice: Everyone makes mistakes” presented the three most common and general mistakes made in the microservice pattern usage regarding the applicational design. Perhaps, for wise people, they are a shortcut to “learn from their mistakes” following the “Middle way” path and two of the eightfold path, namely “Right View” and “Right Effort”.

The second part deals with architectural design mistakes [8], which are related to the fallacies of distributed computing [5].

--

--

--

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

CS 373 Fall 2020: Benjamin Miller

Hash Tables In Distributed System

Preventing Flaky Tests

Common git questions and answers

Why I love Java

INDUSTRY USE CASES with Demonstration on Kubernetes

State of Matterless #15

ETL with Azure Functions, Python and Pandas | QueryClick

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Alessandro Gerlinger Romero

Alessandro Gerlinger Romero

More from Medium

Design patterns for Microservices.

Introduction to Monolithic Architecture and MicroServices ArchitectureMonolithic Architecture

Proxy Design Pattern

An Introductory Guide to Microservices Architecture

An Introductory Guide to Microservices Architecture