Preamble
In this series of posts, I am going to discuss the various benefits of microservices as an architectural pattern. I will try to cover aspects that are either not being discussed on the web at all or are being discussed, but not deep enough.
All development patterns, as a rule, have their pros and cons. Thus, the advantages are often subjective and the developer should choose the appropriate models depending on the conditions and context.
I will try to isolate objective or near-objective advantages - advantages that will give a positive effect to any developer, regardless of programming language, team size or diet. The first article is devoted to the cost of poorly written code - we compare the effects of such code on monolithic applications and microservices.
In addition, later, when several articles are typed, I plan to mount a video for YouTube - animations and screencasts will convey my point of view more clearly.
')
Introduction: How conventions and frameworks improve confusing code
When you write a program of 100 lines, then, in principle, it does not matter how cool you chose the design or how clearly you follow fashionable ideas. A small application is relatively easy to understand, simply because it is small. And to start optimizing it would be an anti-pattern in and of itself — such optimization is often called premature.
As a rule, you start refactoring code when you notice how source files have grown or how you repeat the same logic more than two times. But if the application has only 100 lines, how many such repetitions can actually fit?
And then your boss asks for more and more features, and your application starts to grow. Now it does not make sense to keep all the logic in one file, you need to split the application into several files. And when there are a lot of files, you start organizing them into folders. When there are many files and folders, you are looking for a way to logically sort the elements. You are probably starting to divide the source files into models, controllers, and so on.
The danger of tangled code begins to appear - file X refers to file Y, Y depends partly on file Z, file Z imports several functions from files A and B. A younger developer comes, changes one file and the entire application breaks, and you have to correct the error before boss will call the first angry customer.
To solve the problem came to us frameworks. Frameworks often impose their own conventions (rules), systematically splitting applications into files and directories. For example, controllers should deal only with web requests, model classes should contain business logic, templates should contain only HTML, configuration should be stored in a separate place and preferably depend on the current environment.
Want to add a resource? Change the route file!
Do you want to add additional logic that starts after saving the record? Sign up for an event!
Want to add additional conditions for queries to the database? Create a table behavior class!
And so on.
This not only helps to develop larger monolithic applications, it is the only way to develop a large application and not go crazy! If every team member has the right to add code anywhere, your development process will run out of control pretty quickly.
Let's look at the structure of an empty application on Ruby on Rails:
./app/assets ./app/assets/config ./app/assets/images ./app/assets/javascripts ./app/assets/javascripts/channels ./app/assets/stylesheets ./app/channels/application_cable ./app/controllers ./app/controllers/concerns ./app/helpers ./app/jobs ./app/mailers ./app/models ./app/models/concerns ./app/views/layouts ./bin ./config ./config/environments ./config/initializers ./config/locales ./db ./lib ./lib/assets ./lib/tasks ./log ./public ./test ./test/controllers ./test/fixtures ./test/fixtures/files ./test/helpers ./test/integration ./test/mailers ./test/models ./tmp ./vendor ./vendor/assets ./vendor/assets/javascripts ./vendor/assets/stylesheets
The reality is that your team may have inexperienced (or hangover) colleagues who seem to break simple conventions from time to time, and the code will get harder and uglier, despite the choice of the “right” framework and structure.
Writing good code is especially important in the context of a large application. SOLID principles, development patterns, frameworks, and conventions first appeared to help the developer with large applications.
Monoliths and microservices: Effect on spaghetti code
This is what microservices do with spaghetti:
Oh, not that picture. This is what a spaghetti code looks like in the case of a monolithic application:
One class (or function) calls another class, and that class depends on another class, and that class depends on several other classes, and so on. You want to run through the code and correct the error - be prepared to open many files and study them in parallel. Why do I think that this is a characteristic of a monolithic application?
In a monolithic application, the modules (elements) of the code call each other directly — using the fact that they are all loaded into the working memory within one machine. This leads to the fact that lazy developers are too closely connected parts of the application among themselves.

Microservices, on the other hand, usually communicate via web requests (usually RESTful) or via messages. Thus, the developer cannot simply take and call the functionality of one microservice from another microservice - at least, it is necessary to create an additional route, open this method in the controller, and so on. This is additional work, a barrier that developers will not overcome without absolute necessity. There is also a possibility that the other microservice is currently supported by another team of your company, and the developers are harmful there and they don’t want to add an unnecessary (from their point of view) route just to make your life easier.
As a result, you are likely to have fewer, better organized connections. And the fact that there are fewer dependencies between microservices (various functional modules of your application) means that if microservice A is poorly implemented, it will not have such a bad effect on other microservices.
In the environment of microservices bad code is isolated.
Microservices: Calm Your Internal Perfectionist
Since a single microservice is nothing more than a class or two, cut from your monolithic application, now you have fewer, much fewer files within one open application in the IDE. Thus, you probably no longer need to worry so much about the strict rules for naming files and folders, and perhaps you can even weaken the SOLID rules.
Now you can afford a “freebie” - you can make a few mistakes, a few suboptimal implementations, and your application is still quite easy to read and edit, because your LoC (Lines of code) has dropped from a few thousand to a dozen dozens or hundreds!
The development process will speed up because you are less concerned with strict rules and a myriad of dependencies!
Conclusion
Microservices, as an architectural pattern, can reduce the cost (cost of) non-optimal source code, speed up development and improve the quality of sleep.