Hello! Welcome back to our course on preparing for microservices interviews.
In our last lesson, we explored the Twelve-Factor App methodology, which provides a blueprint for building cloud-native applications. These principles define the ideal state for the microservices we aim to build. However, in the real world, we rarely start with a blank slate. More often, the challenge is to evolve an existing monolithic application.
This lesson directly tackles that challenge. We will describe proven strategies for migrating from a monolith to a microservices architecture. A deep understanding of these patterns is a hallmark of a senior engineer and a frequent topic in system design interviews. You'll be expected to discuss not just the "how," but also the "why" and the associated trade-offs.
By the end of this lesson, you will be able to describe strategies for migrating from monoliths to microservices, with a detailed focus on the Strangler Fig pattern.
1. The Migration Dilemma: Why Not Just Rewrite Everything?
When faced with a large, unwieldy monolith, the first instinct for many engineering teams is to plan a "Big Bang" rewrite: halt all new feature development on the monolith and dedicate a large team to building the new microservices-based system from scratch. While it sounds clean on paper, this approach is notoriously risky and often fails.
To understand the significant business and technical risks of a Big Bang rewrite, let's watch a short segment from this video.
Monolith to Microservices Migration | Microservices Tutorial
This video, titled 'Monolith to Microservices Migration' from the Selenium Express channel, clearly articulates the pitfalls of the 'Big Bang' approach. Understanding these pitfalls is crucial for justifying an incremental strategy in an interview.
Watch the section from 02:00 to 05:57. Focus on the three main problems the speaker identifies: communication overhead in a large team, the inability to provide accurate deadlines, and the negative impact on the business from halting new feature development.
As you saw, the Big Bang approach freezes business innovation, creates immense project risk, and reintroduces the same communication problems we're trying to solve by moving away from a monolith. This is why experienced architects advocate for incremental, continuous migration strategies.
2. The Strangler Fig Pattern: A Safer Path Forward
The most widely accepted strategy for incremental migration is the Strangler Fig Pattern. The name is an analogy from nature: a strangler fig vine starts small on a host tree, gradually growing around it and putting down new roots until it eventually replaces the original tree entirely.
In software, this means we gradually "strangle" the monolith by incrementally implementing new functionality as microservices and routing traffic to them, until the old system is either gone or has shrunk to a manageable size.

The key component that enables this pattern is a routing layer, often called a "Strangler Facade." This is typically an API Gateway or a reverse proxy that sits in front of the entire system. Initially, it routes all traffic to the monolith. As you build new microservices, you reconfigure this router to send specific requests to the new services instead.
This video provides a great visual walkthrough of how the Strangler Facade works in practice.
Monolith to Microservices Migration | Microservices Tutorial
Let's return to the 'Monolith to Microservices Migration' video. This segment provides a clear, animated explanation of the Strangler Fig pattern and the role of the gateway.
Watch from 12:05 to 17:59. Pay close attention to how the 'Strangler Facade' (or proxy) intercepts user requests and decides whether to route them to the old monolith or the newly created microservice.
The Strangler Fig Pattern in a Spring Ecosystem
Since your background is in Spring Boot, let's look at how this pattern is implemented using familiar tools.
Strangler Fig Pattern to migrate from a Monolithic Java Application to Spring Boot Microservices
This article, 'Strangler Fig Pattern to migrate from a Monolithic Java ...', provides a concrete example using Spring Boot. It shows how the abstract concepts of the pattern translate into specific technology choices.
Read the sections 'Introduction', 'Applying the Strangler Fig Pattern', 'Step-by-Step Migration Process', and 'Results & Key Takeaways'. Notice how technologies like Spring Cloud Gateway are used as the Strangler Facade, and how other tools like RabbitMQ and Kafka facilitate communication in the new architecture.
As the article highlights, using a tool like Spring Cloud Gateway as the Strangler Facade is a natural fit. You can define routing rules that map specific URL paths (e.g., /api/v2/fraud-detection) to a new microservice, while all other traffic continues to flow to the monolith.
3. Executing the Migration: A Step-by-Step Guide
Knowing the pattern is the first step. Executing it requires careful strategic decisions.
Step 1: Choose the First Service to Extract
You don't want to start with the most complex or critical part of your system. A good candidate for the first migration is a module that is:
- Frequently Changing: Migrating a part of the system that is a development bottleneck will deliver value quickly.
- Relatively Self-Contained: Look for a module with fewer dependencies on other parts of the monolith. This minimizes the complexity of inter-service communication.
- Resource Intensive: If a specific feature (e.g., reporting or search) consumes a disproportionate amount of resources, extracting it allows you to scale it independently.
The video below offers excellent guidance on this selection process.
Monolith to Microservices Migration | Microservices Tutorial
Let's watch one more segment from the 'Monolith to Microservices Migration' video. It directly addresses the question of which service to migrate first.
Watch from 05:57 to 10:49. Focus on the idea of analyzing your project's history to identify modules that are responsible for the most code changes and conflicts.
Step 2: Define Communication Between the New Service and the Monolith
Once you've extracted a service, it still needs to interact with the monolith. A common path for this evolution involves a few stages. This is a critical topic for senior-level interviews, as it demonstrates your understanding of architectural trade-offs.
Splitting up a Monolith to (micro)Services
The video 'Splitting up a Monolith to (micro)Services' by CodeOpinion offers a more technical view of the migration process. It details the evolution of communication from in-process calls to asynchronous messaging.
Watch from 02:12 to 06:25. This covers three key stages: Replacing in-process calls with synchronous, out-of-process RPC (like REST APIs), often while still sharing the database. Giving the new service its own dedicated database. Moving from synchronous RPC to asynchronous messaging for better resilience and autonomy.
This phased approach is important. Jumping directly to asynchronous messaging might be the end goal, but using synchronous REST calls as an intermediate step can be a pragmatic way to make progress faster, especially if the monolith and the new service still share data.
Step 3: Handle the Data
Data is often the hardest part of a migration. Initially, the new service might read and write to the monolith's database. However, the ultimate goal of a microservice is to own its own data. This introduces significant challenges:
- Data Migration: How do you move data from the monolith's database to the new service's database without downtime?
- Data Consistency: How do you handle transactions that now span the monolith and the new service? This is where patterns like Sagas become necessary, which we will cover in Module 4.
- Data Duplication: During the transition, you might need to write to both the old and new databases simultaneously (a technique called dual-writing) to keep them in sync.
Test your understanding!
You are tasked with extracting a NotificationService from a monolith. The monolith's Order module calls a sendEmail method directly within the Notification module after an order is successfully saved to the database.
How would you apply the Strangler Fig pattern and the communication evolution we just discussed? Describe the steps.
Show answer
- Extract the Service: Create a new
NotificationServiceas a separate Spring Boot application. - Introduce an Intermediate Communication Layer: In the monolith's
Ordermodule, replace the direct method callnotificationModule.sendEmail()with a REST API call to the newNotificationService's endpoint (e.g.,POST /api/notifications/email). The monolith and the new service might still share the same database at this point. - Introduce the Strangler Facade: No facade is needed yet for this specific backend flow. The facade is primarily for intercepting incoming user traffic, not for internal, service-to-service calls. The change here is internal to the monolith's code.
- Isolate the Data: Create a new database schema for the
NotificationService. Migrate all notification-related tables (e.g., email templates, sending history) to this new database. - Evolve to Asynchronous Communication: To improve resilience, change the communication pattern. Instead of a synchronous REST call, the
Ordermodule in the monolith would publish anOrderPlacedevent to a message broker like Kafka or RabbitMQ. TheNotificationServicewould subscribe to this event and send the email asynchronously. This decouples the services completely.
4. Answering the Interview Question
In an interview, you'll need to present these ideas in a structured way. Here's a framework based on a typical interview question.
Question: "You have a critical monolithic application that's difficult to maintain. Outline a phased strategy for migrating it to microservices. What are the biggest technical and organizational challenges you anticipate?"
Monolith & Microservices tough questions & answers for interviews
This article, 'Monolith & Microservices tough questions & answers for interviews', directly addresses this common interview question. It provides a well-structured answer that you can adapt.
Read the answer to question #2, 'Evolution Strategy'. Focus on how it outlines the phased strategy using the Strangler Fig pattern and then lists the key technical and organizational challenges.
Your summarized answer should look something like this:
"My preferred strategy would be the Strangler Fig Pattern, which allows for a gradual, low-risk migration without halting business-critical feature development.
The Phased Strategy would be:
- Analyze and Identify Boundaries: First, I'd analyze the monolith using Domain-Driven Design principles to identify a good candidate for extraction—a module that is relatively independent or a major source of development pain.
- Introduce a Strangler Facade: I'd place an API Gateway in front of the monolith to act as a routing layer.
- Build the New Service: Develop the new microservice, ensuring it has its own CI/CD pipeline and follows 12-Factor principles.
- Gradually Redirect Traffic: I would configure the gateway to route a small percentage of traffic for that specific functionality to the new service. We could use techniques like A/B testing or dark launching to validate it with live traffic before a full cutover.
- Decommission and Repeat: Once the new service is stable and handling all traffic for its domain, we can remove the old code from the monolith and repeat the process for the next domain.
The biggest challenges I anticipate are:
- Technical Challenges:
- Data Consistency and Migration: This is the hardest part. Managing transactions that span the monolith and new services requires patterns like Sagas. We'd also need a robust data migration strategy, possibly using dual writes or Change Data Capture (CDC) to minimize downtime.
- Inter-Service Communication: We'd need to standardize communication patterns, whether synchronous REST or asynchronous messaging, and implement resilience patterns like retries and circuit breakers.
- Organizational Challenges:
- Team Structure: We would need to shift from component-based teams to cross-functional teams that own their services end-to-end.
- Cultural Shift: The organization must embrace a DevOps mindset and get comfortable with distributed systems concepts like eventual consistency and failure as a normal occurrence."
Conclusion
Successfully migrating a monolith is a journey, not a destination. It requires a blend of technical expertise, strategic thinking, and organizational change management. The Strangler Fig pattern provides a proven, pragmatic roadmap for this journey.
Key Takeaways:
- Avoid the Big Bang rewrite due to its high risk and negative business impact.
- Embrace the Strangler Fig Pattern as an incremental, low-risk migration strategy.
- The pattern relies on a Strangler Facade (like an API Gateway) to gradually redirect traffic from the monolith to new microservices.
- Choosing the first service to extract is a strategic decision based on factors like rate of change and module independence.
- Data migration and consistency are the most complex technical challenges in any migration project.
Next Up
Now that we've discussed how to extract new services from a monolith, the subsequent lessons in this module will focus on making them robust and production-ready. In our next lesson, we will cover a fundamental aspect of operability: implementing health check endpoints using Spring Boot Actuator for service monitoring.
Can't find a good explanation? Sign up and we'll make it for you
Sign up