TO SPLIT OR NOT TO SPLIT THE MONOLITH
As you think about legacy code, it's helpful to remember two things. First, it's been running your business this long and got you to where you are today. That is something to celebrate. Second, today's modern technology is just tomorrow's legacy
Nowadays, software products play a significant role in business development. Software and analytics instruments provide the daily activities of companies and support their decision making. Therefore, organizations are trying to find new technical solutions to enable their applications to be more agile and scalable. One of the trendy practices for improving software, simplification its support and maximizing profits is the adoption of microservices.
Such corporate giants as Netflix, Amazon, and Uber decided to migrate some monolith applications to microservices. However, does it mean that microservices are better than the monolith architectural style? In this article, we ague this issue.
What Is A Microservice Architecture And Why It Is Often Chosen
Speaking of the current software paradigm, two types of solutions are widely used: microservices and monolithic architectures. In general, microservices architecture represents an application as a collection of small, loosely coupled services. In this kind of solution, the complexity is moved to the level of coordination of services. Each service represents one business capability that makes it easier to locate the code.
Whereas monolithic architecture assumes several discrete functions composed into a single unit that is tested, deployed, and scaled as a whole. All components are interdependent and often cannot run separately. That also means a bug in a module can slow down or break the entire application.
Microservices Architecture. Pros & Cons
Like every solution, microservices architecture has its advantages and disadvantages
When To Choose Microservices
Martin Fowler (2015) gives advice on how to build useful software: “Almost all the successful microservice stories have started with a monolith that got too big and was broken up” Amazon pioneered the microservice architecture. In 2001, the company found itself unable to keep up with the scaling demands of its rapidly growing customer base. Due to countless requests from a wide variety of applications, the company faced coding issues, development delays, and service interdependencies. To figure out the refactoring of its system from scratch, Amazon broke its monolithic applications into small, independent service-specific applications. One service accepted orders, another one generated a list of recommended items to buy, and one more was a simple authentication service.
It is the wrong approach to choose microservices just following modern trends. However, heavy system load or the necessity to interact with different payment systems requires software architecture, and code to be designed in a way that supports it.
Moving to microservices is the right choice for business in some cases:
- The need to overcome growth and scaling challenges. If your monolithic application has become too inflexible to upgrade. There are system outages and the need for scaling
- Accelerated time to market. To succeed in a competitive business environment, you need to quickly develop and release applications, updates, and new application features
- Business intelligence, artificial intelligence. You need to implement advanced business intelligence solutions to get deeper and more competitive business data, reports, and analytics
- IoT Networks: You need to build an IoT network and your current infrastructure cannot provide the required horizontal scalability and cannot handle the huge data processing load
Amazon Microservices Infrastructure, known as the Death Star. 2008 Source
Challenges When Moving to Microservice
There are some challenges that companies may face during the migration from a monolithic architecture to microservice architecture. The adoption of microservices poses technical and organizational issues, and it is really important to understand them. So, now we discuss the risks:
- It is extremely difficult and time-consuming. You need to understand that the migration of the monolith can take a lot of time and efforts. This is why the refactoring toward microservices should be done in a small parts. The company has to pay developers, but in fact, the project will be not developed. You should carefully organize a development team if you want to develop new features despite the migration process.
- It is very expensive. Expensive not only from the point of the development and code writing, it is expensive from the point of support, operation, and making changes. It requires significant investments in building infrastructure, developing documentation and refactoring applications.
- Microservices is a distributed system. That means the development team needs to choose and implement an inter-process communication mechanism based on either messaging or RPC.
- Moving of the codebase. The extraction of microservices from existing monolithic is dangerous for the data and code bases. It is extremely important to be careful during refactoring because there is a possibility of introducing new bugs. That is why good test coverage is needed.
- Organizational challenges. The organization must split big teams to smaller ones which can work autonomously. This way the structure of organization is on the line with the structure of architecture.
- Teams take responsibility of their service. Teams own their codebase, and they are in charge for the service functionality. And they cannot blame someone else in failure. If there is a problem in the product the team has to fix it.
- Manage the migration process without stopping the system. Users should have access to the application.
These issues demonstrate that a microservice architecture may not always be beneficial for startups and midsize companies as it needs resources.
Migration. Where To Start: Audit and Analysis
Moving from a Monolith architecture to a Microservices might take years. How do you know if it is right for your organization? Sam Newman, the author of a book on microservice migration patterns, offers developers to consider three questions before adopting a microservice architecture:
- What are you hoping to achieve?
- Have you considered alternatives to using microservices?
- How will you know if the transition is working?
Before deciding to move a monolith to microservices or change the architecture, it is very important to assess how necessary it is for the product. As we mentioned, it is very expensive and time-consuming, and there are big risks. Based on Sam Newman’s recommendations and due to our experience, we propose an analysis approach:
Set up the goals
- Why you might want migration and when you cannot avoid it.
- Form a set of outcomes that the business is trying to achieve and described the benefits for the end-users of the system. Clarify what you want to gain moving to microservices. It might be rapid development or you need to reduce interdependence of services, increased uptime, or scalability.
- Measure the expected load on the system and the number of users.
Think about alternatives.
- The decision about migration may be connected with a heavy load, then you need to opt:
- Move part of the functionality. It depends on the project. The functionality of sending an email, push notification or phone call is not tied and can be divided. But if we have a system of the dashboard, where analytics is collected from the linked database, it will be almost impossible.
- Analyze the current functionality and optimize it. Reconsider what creates downloads on the main project: suboptimal database queries or a large amount of unnecessary information. May be it is nesessary to update the hardware. Develop new features and bring them to microservices.
- Try to apply vertical or horizontal scaling.
Evaluate your DevOps team maturity level
Your teams need to understand core DevOps practices. Is there a general culture of automation? Does your operations team support scripted deployments? What about Infrastructure as code? Do you have standards for how to do a code review? If you have mature development and operations practices, then a microservices architecture might be good for you.
Take inventory of business functions and capabilities
You architects should find associated code objects and match them to business functions in the system. Many functions cannot be moved because their domain has not been clearly defined. The technical team must understand how problematic it is to divide all the functionality into microservices. For example, there might be a situation where each entity is tied to several other entities. In this case, it is impossible to split it into a normal microservice. The logic of the business process may be very confused.
Make sure you can get rid of the dependency loop
Dependency cycles are sometimes impossible to avoid, but they create a connection between services, then blur their boundaries and offer to combine them into a single module.
Clarify if you can create cross-functional teams
They should include developers, QA, operators, and business owners. Microservices need a different command structure. Create teams that can design, build, deploy, and maintain service without the need for any approval process. "We try to create teams that are no larger than can be fed by two pizzas". Jeffrey Bezos called it "the two-pizza team rule."
Choose the scaling platforms.
You need soft that can scale resources for microservices or to support autoscaling. As a solution option, you can use a serverless infrastructure hosted by cloud providers (such as Google Cloud, Microsoft Azure, and Amazon Web Services).
Then you should consider how to build a process not to damage the user experience. Engineers together with customers conduct business requirement analysis and construct a detailed data flow of business logic. It should not be changed while a migration.
You Decided To Split. Step By Step Instructions
The migration of monolith systems to the microservices architecture is a complex problem that software development teams have to solve. Now we summarize some experiences and instructions how to adopt microservices.
Correct microservice boundaries is the base of healthy microservice architecture. In case of false boundary measures, a change in functionality in a new microservice leads to a change in functionality in other microservices. As a result, the interfaces of all dependent microservices will "float" with subsequent integration tests. And if these microservices belong to different teams, they faced with inter-team meetings and approvals.
A vivid example of what may cause domain separation is the software company Istio. They have confirmed that they are moving back from a microservices architecture to a monolith to make it easier to develop their products and meet some business requirements with less effort.
After migrating to microservices, the Istio team started getting feedback from their users, they soon realized that microservices weren't as useful as they initially thought. The main reason was that all control plane services were deployed and used together and shared the same administrative and security domains. Thus, moving the Istio control plane to a monolithic architecture was a good decision, as it greatly reduced the operational complexity of Istio. So, make sure that the monolith can be broken according to technical criteria. Recognize business domain boundaries within architectures and enforce them using public APIs as interfaces.
Highlight the functionality in a monolith, which can be moved
It is important to determine which functional groups provide the most value as microservices. The rest of the functionality can be left in a monolithic system for now. A team of engineers and domain experts will walk you through existing implementations, dependencies, and internal events. Non-technical experts will point out things that are missing from your services, or features that may be critical in the future.
Separate data store for microservices
Each microservice should have one data repository. Note that separating data can make it more difficult to manage. Individual storage systems can easily get out of sync or become inconsistent. Therefore, you need a tool that performs master data management (MDM). Let's say it can check each database of subscriber IDs to make sure that the same IDs exist in all of them. Ensure the safety of user data, even if the service stops working. Initially, it is better to store data both on the microservice and in the monolith table.
Keep code of a microservice
Instead of adding or rewriting a piece of code in a well-performing deployed microservice, it's better to create a new microservice for the new or changed code. This way, you can deploy and test new code without the risk of failure in the existing microservice.
Separate build for microservice
Do a separate build for each microservice. Thus, it will be possible to obtain component files from the repository at the appropriate revision levels.
Deploy microservices in containers
To deploy a microservice, it's better to use a container, so you only need one tool. Note that Docker is advised as the standard for containers.
Avoid “Snowflake” systems
Treat microservers as interchangeable members of the group. The one that stops working is automatically replaced by another. Avoid "snowflake" systems, do not rely on separate servers for specialized functions.
Some Cases To Now
See successful practices for implementing a microservices architecture
Main Reason. To overcome the scaling challenges and service outages. Back in 2008, a single error caused massive data corruption and led to days of downtime. The company needed an architecture that allowed Netflix to operate 24/7, scale to the next order of magnitude, and optimize speed.
The microservices architecture allowed Netflix to split the system into independent services: one service stores all the shows watched, another is responsible for monthly credit card payments, the third analyzes the viewing history and offers similar shows and movies.
Main Challenges. It takes a full seven years to complete the migration. There were a lot of latency issues with the web pages, when Netflix first moved the customer-facing website to the cloud. There was an outage in AWS US-East that brought down several popular websites hosted on AWS.
Best Practice. Netflix decided to move away from vertically scalable single points of failure, such as relational databases in our data center, in favor of highly reliable, scale-out distributed systems in the cloud. They chose Amazon Web Services (AWS) as a cloud provider because it gaves the most scale and the widest range of services and features. Netflix denormalized the data model using NoSQL databases.
Netflix Microservices Infrastructure
Main Reason. To reverse a massive technical debt that had created serious stability issues. Since applications were interconnected, bugs in one part of the system had the potential to bring down our whole system. Main Challenges. Issues of handling communications among microservices, addressing failures, and debugging problems Best Practice. To invent new integration and end-to-end testing patterns and foster a new internal culture around these guidelines. To implemente its own JSON/RPC protocol, and built a microservices framework on top of SpringMVC
Main Reason. To deal with the needs of a "hyper-growth company." For a company experiencing exponential growth, a microservices design helps to continually iterate to match new demands
Main Challenges. Organizational changes. There were many opinions and conflicts due to differences in communication in the organization structure and in building communications around microservices
Best Practice. Usage of such tools, as Minikube and Docker helps run services locally, and runs them remotely. All microservices are in Node.js; therefore they leverage npm-based packages such as Ava for unit testing, NYC for Istanbul’s code coverage module, and XO for linting
Main Reason. Interdependent architecture became an issue for deployments. downtime was too long to sustain for conducting business online Main Challenges. Building trust. There was a cultural resistance to how software is built and deployed. Teams used to pack features upon features into infrequent releases, and then they had to deal with changes how they do their jobs
Best Practice. CI implementation and deployment tools such as Chef and Jenkins. However, the biggest change was moving to Riak, a distributed NoSQL key-value data store.
We had the experience of moving rather large functionality to microservices. It was the basic functionality that everything relied on. It really takes time, as you need to figure out how the project works, and what the interdependences are there. In particular, we faced the problem of moving a cyclic dependency. The company we worked for was quite big. And one of the challenges was that the monolith itself changes during the process of migration. It extremely difficult to manage the work so that no one uses the site during the break of monolith application.
We also migrated certain entities of the system. There were no problems when moving isolated functionality to a separate service in microservices. However, in any case, you need to be very careful when migrating data and ensure their compatibility.
So, should we keep up with new architectural decisions or stay with monolith? Actually, there is no final answer. Microservices architecture is neither good nor bad, it is just a different way of building software. The decision depends on the business needs of application.
The customer and development team must find the common solution. Let's say that the project does not plan high loads and interaction with external services, in this case it is better to choose a monolith. On the other hand, if the system must work under any load and with a large number of services, then a microservice architecture is the best option.
A lot depends on the organizational structure of your business. Do you have several IT teams working on the same product? Microservices may be suitable. But if you have one team of several developers, they will build and maintain the monolith well.
It is up to you to decide, just be sure your solution is reasonable. In certain situations, it may be easier to start with a monolith. Let your services grow inside a monolithic application, and only then start moving them to independent services. The choice is yours.
Contact us to get detailed consultation about microservices