iTranslated by AI

The content below is an AI-generated translation. This is an experimental feature, and may contain errors. View original article
🐥

Why "Microservices APIs" Was Boring

に公開

Introduction

Recently, I purchased the book Microservice APIs in Action.
My motivation was to learn about the microservices methodology in order to implement them.
I was reading the book for that purpose, but it was quite a struggle to read from the perspective of microservice API implementation.
In this article, I would like to discuss why it was such a struggle.

Notes Before Getting into the Main Topic

Before diving into the main topic, I would like to mention two points.
First, I do not mean to say that the book itself is boring.
Although the title "Why 'Microservice APIs in Action' Was Boring" might make it seem like a bad book, the book itself is definitely an incredibly wonderful book.
It starts with an overview of microservices and covers a wide range of topics, including design considerations for microservices and API implementation.
Furthermore, it touches upon authentication and authorization using JWT, testing methodologies, and even deployment methods using EKS.
As you can see from its 458-page volume, there is much to be learned regarding what to consider and the actual techniques for implementing microservices.
My favorite part in particular is the section explaining GraphQL API implementation.
While the overview of GraphQL and the explanation of Query and Mutation syntax are brief, it introduces what to keep in mind when implementing APIs for practical use.
For someone like me who prefers to try things out first and grasp the overview later, what I learned from this book was very valuable.
As mentioned above, Microservice APIs in Action is an excellent book.
Please understand that I chose the title to make the main point more impactful, and it is not intended to diminish the value of the book itself.
Second, I will hardly mention the infrastructure aspects that are essential to microservices.
In order to run services independently, there are many tasks in the infrastructure layer, such as container management with Kubernetes and collecting logs from each service to facilitate root cause analysis of errors.
However, I will not touch upon such topics here.
There are two reasons for this.
One is that my own understanding is shallow, so if I were to include these topics, it would take a long time before I could complete this article.
The second is that the main theme of this article focuses on the implementation of APIs for building microservices.
This second reason is the primary reason for not touching on infrastructure; I am focusing solely on the point of implementing APIs. From that perspective, I am attempting to conclude that Microservice APIs in Action was boring.
Infrastructure does not play a part in the main theme this time.
While infrastructure is important for building microservices, it is irrelevant here and has been omitted.
These are the points I would like you to read before moving on to the content of this article.

About Microservices

What are Microservices?

First, let's look at microservices themselves. While there is no perfectly fixed definition of microservices, Sam Newman, the author of Building Microservices, mentions the following:

Microservices are small, autonomous services that work together.

Also, this article describes the microservice architectural style as follows:

In short, the microservice architectural style [1] is an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms, often an HTTP resource API.

Roughly translated, this means "microservice architecture is an approach to deploying a single application using small services that each run independently and communicate through lightweight protocols, such as HTTP resource APIs." From this, we can see that the following points are important for microservices:

  • They operate independently.
  • They are small in scale.
    • However, "small scale" refers to the service's responsibility being limited to a single domain, rather than just having a small absolute amount of code.
  • They are gathered together to build an application.

Now that we've briefly looked at the overview of microservices, let's look at monoliths, which are often compared to microservices.

Monolithic Applications

Next, let's look at monolithic applications.
Monolithic applications are, as the name suggests, applications where all functions are built into a single project.
For example, consider creating a bulletin board that requires login.
In a microservices approach, you would likely separate the services into a login function and a bulletin board viewing/posting function.
On the other hand, in a monolithic approach, these functions would not be independent but would all be included within a single project.
Since we have also briefly looked at monolithic applications, we will compare monolithic applications and microservices to confirm the advantages of microservices.

Benefits of Microservices Compared to Monoliths

Here, we will look at the advantages of microservices by comparing them with monolithic applications.
First is the ease of avoiding tight coupling in code.
When implementing in monolithic code, accessing the desired functionality is simple.
In fact, you can use the necessary features just by importing them from a file.
While this ease of use is an advantage, it also has the downside that parts tend to depend on each other, often making maintenance difficult.
This is not a problem as long as the application scale is small, but as the application becomes increasingly complex, these dependencies make it harder to modify or extend.
Monoliths face such challenges.

However, these issues are less likely to occur in microservices.
If services are appropriately separated, each function becomes self-contained, which prevents them from becoming dependent.
As a result, modifying one part does not have a major impact on the other, making it easier to modify and extend each function.
Also, testing becomes easier compared to monolithic apps.
In a monolithic app, tests are bundled together, so every time test cases for new functions are added, the time to complete the tests balloons.
As a result, deployment takes longer, making it difficult to reflect small fixes quickly.
On the other hand, since each service in a microservice is independent, adding tests to one service does not affect the tests of other services.
Therefore, the concern that the total completion time will slow down as the number of test cases increases is significantly less than in a monolithic app.
Other benefits include easier refactoring because responsibilities are divided, making it easier to build code that is simple to manage.
In modern times, where creating a single high-performance app is more common than creating multiple small apps with few functions, the concept of microservices brings many benefits.

Challenges of Microservices

I mentioned the benefits of microservices earlier, but of course, microservices also have challenges.
Specifically, there are the following four points:

  1. Need for effective decomposition of services
  2. Difficulty of integration testing
  3. Handling cross-service issues during errors
  4. Increased operational complexity and infrastructure overhead

Let's look at each one briefly.
First, regarding the effective decomposition of services.
Because each microservice is independent, the advantage is that each function can be loosely coupled and easily extended.
However, if the service division is not performed appropriately, one service will end up being dependent on the other.
This not only cancels out the benefits of microservices but also makes management more difficult than a monolithic app because multiple deployments are required.
This state is called a distributed monolith, and when building microservices, it is necessary to consider designs to avoid this state.

Next is the difficulty of integration testing.
Earlier, I said that microservices are easy to test, but that is when testing them in isolation.
In integration testing, where multiple functions are combined and tested, microservices are harder to handle than monolithic apps precisely because they are independent.
It is necessary to understand that this difficulty in building integration tests exists in microservices.

The difficulty of dealing with combinations of multiple functions also exists when an error occurs.
As an example, consider an ordering service and a shipping service.
Assume the proper flow is to perform order processing in the ordering service and then shipping processing in the shipping service.
In this case, if an error occurs in the ordering service, rolling back is easy in a monolithic app.
Since a single database is used, you only need to roll back that database.
On the other hand, in microservices, each service may use a different database.
While in a monolithic app you only had to roll back one database, in microservices, you need to detect an error in one part and roll back the databases of each service.
This complexity of performing multiple rollbacks is a challenge for microservices.

Finally, regarding the increase in operational complexity and infrastructure overhead.
Since microservices involve multiple functions operating independently, it is necessary to enable deployment and status management for each.
Introducing a mechanism that allows for this centralized management is a lot of work.
For a single app, it can be done quickly with deployment tools like Vercel, but for microservices, orchestration tools like EKS are used.
The fact that learning costs are incurred makes the introduction of microservices a burden.
Also, because each microservice is independent, when an error occurs in the app, it is difficult to see which service it occurred in.
Therefore, microservices are required to manage app logs in a unified way.
These are the challenges of microservices.
It is clear that each development methodology has its advantages and disadvantages.
Ultimately, it will be necessary to select the appropriate one for each project.

Designing Microservices

Proper Design Principles for Microservices

Microservices are designed to operate independently, have clear boundaries, and interact with each other using lightweight protocols. To fulfill these criteria, there are three design principles:

  • Database-per-service principle
  • Loose coupling principle
  • Single responsibility principle

Let's look at each one briefly.

Database-per-service Principle

Regarding the database-per-service principle, Microservice APIs in Action states:

Each microservice should have its own specific dataset, and it should be impossible to access that data from other services without using an API.

From this, the principle emerges that each service should have its own unique data, ensuring that other services cannot retrieve that data without going through the service itself.
Note that this "specific dataset" does not necessarily mean that each service must have its own separate database instance.
Even if the database itself is shared, it does not violate the principle.
However, it is necessary to ensure that data owned by each service cannot be accessed directly by others.
By following the database-per-service principle, you prevent data from being corrupted by other services and maintain the independence of each service.

Loose Coupling Principle

The loose coupling principle means that services must be designed with a clear separation of concerns.
More specifically, this can be interpreted in two ways.
First, each service can operate independently.
If a service is built on the assumption that it must call another service, the concerns between those services are not clearly separated, and they are considered as a single unit.
Second, each service can be updated without affecting other services.
If other services need to be modified every time a specific service is updated, those services are tightly coupled, and the design should be reviewed.
By adhering to the loose coupling principle, you can achieve proper separation of services and avoid creating dependencies.

Single Responsibility Principle

The single responsibility principle means that services should be designed such that their responsibilities are minimized as much as possible.
Ideally, each service should have only one responsibility.
When applying this principle to microservices, it is best to build each service around its respective domain.

Service Decomposition

Methods for dividing services include decomposition by business capability or subdomains.
Subdomain decomposition is performed using Domain-Driven Design (DDD) methodologies.
To be honest, I hardly understand this decomposition part, so this is as far as I can go.
I apologize.

Why It Was Boring

Up to this point, I have covered the overview of microservices, so I will finally mention why I felt it was boring.

Before that, I would like to re-confirm the purpose for which I purchased Microservice APIs in Action.

I purchased Microservice APIs in Action to implement APIs that can be called microservices.

Therefore, I will proceed with the discussion from that perspective from here on.

There are two main reasons why Microservice APIs in Action was boring.

The first is that the API implementation in the book is focused entirely on adhering to implementation methods already considered "good," regardless of microservices.
I had been implementing monolithic apps all along.
Therefore, I had excessive expectations for microservices, which I was encountering for the first time.
I expected that it would brilliantly solve challenges such as resolving dependencies using new methods I had never experienced before.
However, when I opened the cover, the key to API implementation in microservices was to follow the methods established by our predecessors more strictly than ever before.
In fact, many of the explanations of microservices we have seen so far were things I had seen somewhere else, even if they weren't specifically about microservices.
I think most people have heard of things like the principle of loose coupling or maintaining independence.
Because I was expecting something surprising, it felt a bit like a letdown, and I found it boring to continue reading the book.

The second reason is that I have never developed with a conscious awareness of the principles that should be observed in microservices.
Of course, I have been avoiding excessive dependencies to some extent to improve maintainability.
However, those implementations were done based on intuition, and I hadn't studied or practiced proper theories.
Therefore, while reading Microservice APIs in Action, I understood that the content was important, but there were many times when I felt like I was just scratching the surface without it truly resonating.
Because of my lack of knowledge and experience, the content remained at a level of "Oh, I see," and I wasn't able to truly appreciate that "something important is being written here." This is one of the reasons why I felt it was boring.
From the above, I realized that Microservice APIs in Action is a book that conveys how the things we should value in implementation and design—regardless of microservices—must also be valued when building microservices.
However, because this common sense was not yet common sense to me, and I had excessive expectations based only on the novelty of the terminology, I failed to absorb the core parts of the book and found it boring.
I strongly felt that I need to study more, including Domain-Driven Design.

Conclusion

In this article, I have described why I felt bored while reading the book Microservice APIs in Action.
As I mentioned in the introduction, I have no intention of criticizing this book, and I believe it is excellent.
While I haven't absorbed everything regarding GraphQL, I find it extremely useful.
However, it was a bit premature for me to truly make the core of this book my own.
I wrote this article as a self-reminder so that after I properly learn things like Domain-Driven Design and return to this book, I will not only understand its value but also be able to put it into practice.
I apologize for the repetition, but Microservice APIs in Action is a wonderful book.
If you are not an inexperienced person like me, I believe you can gain even more insight from this book than I did, so I would highly recommend giving it a read.
Thank you very much for reading this far.

Discussion