The pains of microservices - Part 2
In my previous post, I talked about DevOps costs, communication overhead, and distributed transactions. Go check out the previous post if you haven’t read it.
Today, I am going to talk more about the pains that I have seen during microservices development. Okay, let’s get started!
Service Responsibility
Defining service responsibility is hard because it decides how big the service is. Basically, the responsibility of the service decides the granularity of the service. The granularity of the service will affect its scalability. For example, we are going to make a coarse-grained service and we have 20+ APIs inside this service. Now, one of the APIs needs to scale a lot. If we scale this service to support that API, actually it is wasting some resources. Because only one API needs to be scaled. Therefore, controlling the service granularity is important in terms of offering better scalability and the service responsibility can be more focused.
Another pain point is the domain ownership problem.
For example, we need to integrate with multiple notification channels and each channel has its own message templates. In front of those messaging services, we have a notification center to manage the notification requests. Now, the problem is who should own the templates? It seems to put the templates on the downstream messaging service is fine but placing them in the notification center is also fine. This type of domain ownership problem will involve a lot of communication efforts across different stakeholders. If you don’t make it clear in the beginning, it will become tech debt in the future. Should downstream messaging services only focus on “sending” or do they need to manage the templates as well? That will be a question that needs to be discussed across different teams.
Huge Feature Debugging Cost
This is really a nightmare if the feature change involves multiple feature teams and multiple services. Before or during the development, we need a lot of communication costs to talk to different teams and align the requirements and API specifications. In small-scale companies, this seems to be fine. The team size is small, and there are not many communication efforts but in medium or large scale companies, there are multiple teams involved in the feature and everyone has their own opinion. We can’t make everyone happy and it is just the beginning of the feature development. After feature development, we need to test the feature. During this stage, it takes a lot of effort from engineers such as deployment, testing, tracing logs, fixing the issues, and redeploying again. This process takes a lot of time from engineers. For example, if we have 20+ services, we need those service owners to deploy the services and support the debugging and testing. If you are the engineer who needs to support this feature development, how would you feel?
Service Dependency Hell
In a microservice architecture, no one has the full picture of the whole system. Every service is a blackbox, if you are not the owner or maintainer, you won’t have the knowledge to understand what is happening inside. Also, it might have a dependency hell problem when the business grows and we need to support more features. The dependency between service and service is hard to manage and no one can understand the dependency graph. Except this, we need to avoid circular dependency and this will need engineers' effort to decouple the dependency and rethink the design.
Do you know what is the problem of circular dependency? I’ll leave this question to you.
To sum up, although microservices bring some pain points to the team, it is still a good architectural style for large-scale systems if you use this architecture correctly, or else this architectural style will just bring some extra complexities to the engineering team. When you gain something from microservices, you also lose something. This is the tradeoff when making architectural decisions. If your team is willing to pay the cost, then that's it.