Last few years there is a wave of hype which crosses IT-dedicated media back and forth, growing bigger and bigger. And this wave is about microservices.
Countless articles, blog posts, videos and slideshows dedicated to microservices, how to design them or how to apply them to existing applications.
There are also some rare publications with more sober look at microservices. This article is my attempt to amplify this voice of wisdom.
First of all: I have nothing against microservices. Moreover, I'm pretty sure that in some cases they are completely reasonable solution. I'm just as well aware that majority of microservices enthusiasts, who want to apply this approach often barely understand all consequences. That's true that microservices provide benefits, but these benefits could be achieved only under specific conditions. And these conditions are integral part of the microservices solution.
It's rarely mentioned but generally everybody understand that software development is a kind of engineering activity. And just like any other engineering discipline it follows some common patterns and approaches.
Basically this is why for long time waterfall development model was used: this classical engineering approach works quite well for other engineering activities.
But even very first attempts to apply classical engineering approaches did show that despite all similarities software development is significantly different from other engineering disciplines. And the main differentiation point is the complexity. Beside regular complexity which appears just because there are many "moving parts", there are also interactions and dependencies between these moving parts. Interactions and dependencies which often even hard to take into account just because we have no idea about them. Various software vulnerabilities are often results of some kind of internal interactions or dependencies which were not taken into account.
So, whole history of the software development is the history of war against complexity. Structural programming and OOP, function libraries and (very) high level languages - just a very few examples of attempts to cope with this complexity. And once we discover any new way to reduce the complexity we immediately use it to build even more complex systems, so this war never ends.
Lets look at microservices from the complexity point of view. There are two main contributors to complexity of the system build with microservices.
First source of complexity is initial complexity of the application. Here comes first unpleasant surprise: microservices turn software inside out and expose all internal dependencies and interactions. This definitely makes each particular microservice simpler and in the same time makes infrastructure a whole lot more complex.
Second source of complexity is the (often forgotten) fact that any system built with microservices is a distributed system. And every distributed system has a whole bundle of issues specific to distributed systems, from connectivity problems to consistency and distributed clock issues.
As mentioned above internal application complexity is shifted into infrastructure once we start using microservices. This makes infrastructure an integral part of the application. This fact is not often mentioned and even less often clearly understood: in order to successfully apply microservices it's mandatory to have good infrastructure management, all those orchestrations, distributed monitoring/logging, synchronizations, etc. There is no place for shortcuts or adhoc solutions. Price of any mistake is much higher. And since there are many more moving parts probability to make mistake is much higher. So, before trying microservices just ask yourself if your infrastructure is ready for them.
First of all there are two completely different cases - new application and existing application.
For new application use of microservices may (or may not) have benefits, depends on many factors and knowledge of distributed systems and their issues among main of those factors. Lack of established infrastructure or understanding of implications of distributed applications results to appearing of unstable systems which are extremely hard to support, develop and maintain. This offsets any possible benefits of using microservices.
For existing applications use of microservices is also rarely a good idea. Most such applications usually designed without relevant considerations in mind. It means that they are:
- not prepared to live in distributed environment
- not expect connectivity issues while calling (previously internal) service
- use per-request or other long living transactions
- doing other things which are perfectly fine for monolith application.
Attempts to switch to microservices for such applications usually end up with distributed monolith - a horror story for every young microservices adopter. It does not mean that using microservices is impossible for such applications. It just means that application should be prepared for the change. And during preparation you may find other way to solve existing problems without need to introduce microservices.