paint-brush
Microservices? Why Not!by@telnoiko
418 reads
418 reads

Microservices? Why Not!

by Konstantin TelnoiDecember 19th, 2022
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

If you're aiming for a rapid development cycle, low development costs, or maybe thinking about splitting your system into independent services, it might be helpful to know the potential pain points of microservices. Some of them you can avoid by optimizing existing code and keeping it tidy. Other problems can be avoided by prolonging the life of the existing system and not having to deal with many costs of microservices. The point of this article is not to dissuade from using microservices, since their benefits outweigh their disadvantages, but to encourage considering the alternative approach and to know when it is worth enforcing them.
featured image - Microservices? Why Not!
Konstantin Telnoi HackerNoon profile picture


Recently I got asked a provoking question - what downsides of microservice architecture can you name? At first, I was surprised since this ubiquitous architectural approach has become almost a gold standard nowadays. A more logical question I would expect is 'why do we use them?' or 'what are the benefits of using microservice architecture instead of monolith?'. Today I want to go through the development costs of a microservice design that are useful to understand and keep in mind.


Here are the use cases where I think twice if Microservices are an option:

  • I don't want to spend too many resources on this
  • I need rapid service product bootstrap
  • I am considering the split of the backend system into the microservices
  • I already have Microservice architecture in place but don't fully understand its restrictions and implications

Addition of fun(damental) complexity

The central aspect that microservice environment introduces is that it is a distributed system. When we split our monolith into many pieces, we must start thinking about the consistency of the data. Request the user makes can now update information in more than one database. In a monolith we have a transaction that can be rolled back. Similarly, with microservices we might have to roll back the change in several services. There are many patterns to handle consistency concerns, but the whole topic will require a lot of thought if this is the first time you encounter it. For example, you might want to look at distributed transactions, saga pattern, outbox pattern, or many more. This particular topic is critical and not trivial at all. You may end up reading about the CAP theorem and wondering what you wanted to do in the first place that required such complexity.

Development process costs

Having distributed system in place brings other hurdles for us. Reliability of a cluster of services, complicated error tracing, and heterogenous programming environment add up to development effort.


Imagine a chain of services communicating with each other. At some point, the network between them will experience problems, or one service will go down or be forcibly restarted to scale up or down. We need to instrument our code retries and exponential backoffs as a result.

To effectively handle errors in production, we will have to embed in our fleet of services functionalities like monitoring, metrics, and log aggregation. With monolith we only can have two possible states - it is either broken or not. With a set of services, hundreds of combinations can result in the complete or partial failure of the whole system.


We all know how exhausting it can sometimes be to find a bug. With the codebase spread evenly across multiple services, there are no automatic code transitions and prompts showing the usage of the method. The lack of this tooling complicates debugging and consequently requires more time for investigation.


Another potential cost of microservice architecture is housekeeping. From time to time we will need to create new services and figure out how to incorporate them into an existing system. It takes more time to design and coordinate everything, and you may end up with much more maintenance efforts than expected. For instance, you might want to try new technology or language with a new service, which by itself is a good thing but comes with an inconvenience for other developers to learn it as well. Bootstrapping services can become a new task and will take time to adapt.


Last but not least, we speak of microservices about multiplying requests and the time for the business flow to complete. Replacing interprocess calls with network ones may result in a critical delay per each call to the application. It is acceptable for most services, but be aware that sometimes it can make a crucial difference.

Infrastructure and processes costs

Maintenance costs also show up in the deployment and orchestration of the services. Companies that use microservices often adopt DevOps culture or hire individual staff.

As I mentioned, if you helped yourself with log aggregation and tracing, you might be saved. But in rare cases, even that won't help because changes we need to apply are out of the scope of our responsibility. In a monolith, you would have followed the code across different modules, understood at least the code path, and then were able to decide if you needed to contact an analyst or some other developer. In the absence of this possibility, you may only hope that the other team will have time and resources for you.


Not only that, but we also need to keep everyone in the context of what is happening outside the team's scope. Since new services and departments emerge, communication costs are also increasing. And here is when the understanding of what we do loosens. We slowly start to lose contact surface with the product and become responsible for only a tiny part of the system.


Let's imagine we have an application comprising different microservices and want to add a new cool feature. First, we need to either create a new microservice or add the part to the existing one. For simplicity, we are going to add it to the existing microservice. We have to go through our API specifications and figure out the right place and format for a new method. We will also need to add cross-cutting support for our feature in all the services that interact with the one we will modify. It could be an update to a database or additional logic to handle new events, or we may need to add a set of new entities to our system. At this early stage, we have to think about new functionality impacting a set of services and not just adding some lines of code to the existing service. Rather than having a system with a simple approach to new functionality, now there is the headache of integration steps.

Conclusion

To sum up, the costs and efforts of maintaining microservices grow exponentially. As developers, we might prefer our systems to stay small and agile rather than distributed coordinated mesh where no single person has the whole picture in mind. The fact that we have to deal with all discussed hindrances not only demotivates and blocks us in every possible way but also makes us focus more on added complexity rather than intrinsic business value.

Thanks for reading and happy coding!