Migration of the monolith to microservice architecture
V. Most common problems during migration
1. No specific plan or timeframe for migration.
A migrated application is usually live software used by existing customers on an ongoing basis. If the migration is performed by the same team responsible for the ongoing development of the product, there is a high probability that the migration tasks will be relegated to the background in favour of the ongoing development of new features for customers and enhancements of existing functionalities. To prevent this, we may create a dedicated team which will only deal with the migration of the system from a monolith to a microservice architecture.
The problem may also be a lack of determination as to which modules and functions are to be migrated first. The solution is, of course, to analyse the existing modules in advance and decide on the migration plan, e. g. based on the expected changes, complexity of the modules, their interdependencies, system metrics, etc.
2. Inconsistent approach to migration and microservices creation.
Theoretically, each microservice can be built based on different concepts, technologies and infrastructures. Nevertheless, a certain level of tools and environments unification significantly facilitates the development and testing of subsequent microservices, especially at the beginning of the migration. Furthermore, it is advisable to select appropriate microservices-specific tools such as API Gateway, microservices registry, microservices performance monitoring tool, etc. It is also significant to prepare an appropriate CI/CD infrastructure at the beginning of the migration, which will support the deployment of the system to various environments.
3. Too much emphasis on using synchronous communication between microservices.
Distributed systems by their nature are subject to partial unavailability of elements of the solution, e. g. one or more microservices. Synchronous communication requires that both the sender and receiver of a request are available and have the ability to process it in a short time. However, this is not always the case. The microservice handling the request may fail or be overloaded with tasks currently in progress. In such a case, the request will end up with no access to the resource or with the request timeout being exceeded.
An asynchronous communication channel, on the other hand, is usually a message sent via a message broker. The broker ensures that messages are persistent and are delivered to subscribed microservices for handling. This type of communication differs from synchronous communication. How? It imposes less stringent requirements on the recipients of the message i. e. the microservices do not have to be active at the same time (the consumer can catch up on receiving and processing the message later when it is online again).
Furthermore, the hardware requirements are also less stringent: the sender’s microservice thread is not blocked as with synchronous communication. Moreover, if the service experiences a sudden load spike, incoming messages will simply queue up instead of causing connection timeouts or crashes.
However, asynchronous communication will not always work. Where immediate, real-time feedback to the user is required (e.g. logging in, searching for information based on live text, etc.) it will be necessary to use synchronous communication.
4. Creating too many microservices.
One of the basic principles of microservices is the so-called single service responsibility principle. This means that a microservice should be responsible for a single function. However, the understanding of this principle is often too literal and results in multiplication of hundreds of microservices, which in turn causes unnecessary organisational overhead related to maintenance and monitoring of so many elements of a distributed system.
Common sense should be used when dividing into microservices. It is better to rely on the method of division according to business subdomains. Then, each microservice will be responsible for such a limited area (the so-called bounded context) related to a particular subdomain of business activities.
More about this approach can be found in the materials on Domain Driven Design
5. Carrying out migrations without adequate technical and domain knowledge.
A microservices style architecture itself adds a significant overhead of complexity to an already existing system. Therefore, it is extremely important that developers involved in the migration have prior experience in microservices design or have sufficient lead time. Similarly, if the migration will be carried out by a new team with no business knowledge in the migrated monolith, then it will be necessary to properly introduce these people to the new business domain, as well as the issues associated with the existing monolithic system.
6. Horizontal migration, instead of vertical migration.
Sometimes, the planned migration is limited to extracting outside the monolith only a part of the front-end concerning a given function or business logic, but without the data model layer. Such a horizontal migration contradicts the main added value of an architecture based on the microservices style, i.e. it does not allow independent development of the extracted function as it leaves some parts of the solution on the monolith side. In contrast to this approach, vertical migration extracts from the monolith all the layers necessary to implement a given area of logic and places them in the new microservice.