Strangler Fig Pattern to Move from Mono to Microservices

businessman-working-remotely-from-cafe
Bob Quillin January 3, 2023

You’ve been given the green light to modernize a legacy system; however, the monolithic application provides core functionality to the entire organization. It has to remain operational during the process. You could leave the existing code in production while developing a microservices-based architecture, but you don’t have the resources to modernize and maintain the old application.

If your modernization projects require continuous operation, then applying the Strangler Fig pattern may be the migration strategy to use. It minimizes the impact on production systems and reduces disruption to the entire organization. So, how does the Strangler Fig pattern facilitate the modernization of legacy systems to microservices?

What is the Strangler Fig pattern?

The strangler fig pattern takes its name from the strangler fig tree. The tree begins as a seed in the host tree’s branches. The seeds produce downward-growing branches until they establish roots in the soil surrounding the host tree. Eventually, the strangler fig replaces the host tree.

The Strangler Fig pattern in modernization operates on the same principle  — replace legacy code with microservices gradually until the old code is replaced. Using the Strangler Fig pattern begins with a facade interface. The interface serves as a bridge between the legacy system and emerging microservice code.

What is a Facade?

The facade interface operates between the client side and the back-end code. When the facade sees a client request, it routes the traffic to the legacy system or a microservice. The facade is removed, and the client communicates directly with the microservices. As microservices come online, the facade sends more traffic to the modernized system until the legacy system no longer exists.  

As developers create microservices to replace existing functionality, they can test individual services, minimizing the risk of operational failure. If a problem arises, programmers can address it quickly as they only work with a single microservice. The facade can continue to route requests to the legacy system until the code can be safely released into production.

However, the efficacy of the Strangler Fig pattern depends on understanding the complexity of the existing code and the resilience of the Strangler Fig pattern facade. 

Understanding Code Complexity

Although the Strangler Fig pattern seems like the perfect solution for modernizing code with minimal risk, its success or failure depends on identifying the functions that should be turned into microservices. It means sorting through lines of code to isolate individual functionality. If the codebase is small, the Strangler Fig pattern adds a layer of complexity that is not required.

However, organizations working with millions of lines of code can use the pattern to segment migration and minimize risk. Identifying and managing patterns contributing to code complexity can simplify the modernization process.

Untangle Spaghetti Code

Spaghetti code refers to legacy applications that lack structure. Without a logical construct for the application, developers struggle to understand how the code flows. Fixing spaghetti code often relies on guesswork, leading to miscalculations and operational disruptions.

Remove Dead Code

Dead code refers to code that runs but appears to have no impact on the application’s behavior. Unreachable code, like dead code, complicates the code base. It exists but never executes. Both coding patterns complicate program logic and increase the likelihood of a dependency being missed.

Avoid Code Proliferation

Programmatic intermediaries can help new applications talk to legacy systems, but objects that exist to call other objects increase the codebase without adding value. In most instances, the middle object can be removed.

Why Facades Must be Resilient and Secure

The facade is what keeps a Strangler Fig pattern functioning. It ensures that incoming traffic is routed to the appropriate back end. If it fails, all or part of the production system could fail. If the legacy system is a critical-path application, resiliency must be designed into the facade.  

Design for Resilience

Resilience should be designed into the facade and include capabilities to help with processing surges from batch updates. Legacy systems often use batch updating for maintaining core information. When those files are sent record by record without throttling, systems can be overwhelmed. Designing solutions that operate in separate environments can reduce cascading failures. Resilient architectures can minimize possible failures during migration.

Build in Security

With high traffic volumes, facades can be vulnerable to cyberattacks. Zero trust architecture can address server-to-server vulnerabilities. APIs expose components of a monolithic system to outside sources that lack strong security. When converting to microservices, protection from external attacks cannot be assumed. Security considerations should be included in any modernization strategy.

Related: Strangler Architecture Pattern for Modernization

How to Use the Strangler Fig Pattern with Microservices

Strangler Fig patterns let developers update code incrementally. There’s no need to shut down the legacy system and risk a failover if the code doesn’t work as planned. Instead, the software is refactored, and the legacy system functions are gradually cut off. The iterative process allows development teams to focus on refactoring a service at a time. It eliminates the need for multiple teams to maintain two systems.

Down-size God Classes

A single class that grows to encompass multiple classes makes moving to microservices frightening for even the best developers. The god class and its thousands of lines of code reside across methods, making them available to the entire code base. Moving or deleting from the god class can have unexpected outcomes because of the difficulty in identifying interdependencies.

With the Strangler Fig pattern, place variables in object-based data structures. Store the god-class code in an object that links to the appropriate structure. Use the data structure in the microservice and reflect the change in the legacy code. As modernization progresses, well-structured code replaces god classes until they no longer exist.

Replace Hard-Coded Statements

Hard-coded statements should be replaced with dynamic services. Java-based applications often use hard-coded SQL statements. These statements inhibit code agility. When creating microservices with the Strangler Fig pattern, these statements can be replaced or removed incrementally until all hard-coded statements are removed. The logic in the legacy system can be disabled, leaving dynamic microservices.

Ensure Data Integrity

Most databases use triggers that execute code in response to events. For example, a financial transaction is sent for authorization, and its corresponding data is placed in a database. A reversal of that transaction is received, which triggers the code to revise the transaction status field. To ensure data integrity, design the new system to capture the data from the legacy system. Eventually, the new database will contain the most recent information. Older data can be purged or archived, depending on the data storage requirements.

Why Modernization Needs Continuous Monitoring

Modernization requires continuous monitoring. For example, checking the security designed into each microservice can ensure a robust security posture when the modernization is complete. Here are three areas to act on when moving to microservices.

Create Seamless Communication

Microservices should communicate seamlessly, whether it’s through APIs or other messaging services. Message gateways should handle routing, request filtering, and rate limiting. Including a mechanism to allow retries if a request fails adds resiliency to microservice implementations. Internal communications can be monitored using existing tools. Service mesh technology can also monitor internal communications; however, implementing a service mesh at the start of a modernization process is not recommended as it adds to the project’s complexity.

Build-in Rollback Capabilities

While the Strangler Fig pattern for microservices can minimize the odds of a catastrophic failure, that doesn’t mean that every service will work. Ensure there are built-in mechanisms that automatically roll back to the last functioning state. Each microservice should report its operational health to ensure operational integrity. 

Eliminate Cascading Service Failures

When a microservice fails, the failure should not impact the rest of the application. A circuit breaker pattern can help with service failures. Circuit breaker patterns can act as a fail-safe to prevent cascading failures. If a service fails, the breaker invokes a retry mechanism. It will retry requests a preset number of times or retry the connection periodically until communication is restored.

Automating Modernization

Assessing a modernization effort takes hours of combing through code. It means evaluating code complexities such as god classes, unreachable or dead code, and code proliferation. Planning involves deciding on microservice granularity. Too many services generate overhead and add complexity. Too few can reduce agility and hamper independent operations. 

Automating assessments using AI-based platforms can save hours of labor and provide a more accurate result. Static and dynamic analyses evaluate the existing codebase for the following:

  • Technical debt
  • Interdependencies
  • Domain boundaries
  • Code complexity
  • Risk

Through the analyses, automated solutions can quantify the effort needed to refactor an application. With the results, development teams can identify a starting point for modernization. 

Related: Four Advantages of Refactoring that Java Architects Love

Reduce Risk and Increase Success with Automated Refactoring

With the right automated tools, monolithic applications can be modernized and deployed quickly. vFunction’s Code Copy can identify dependencies, divide services by domain, and introduce newer frameworks. It’s a multidimensional analytical approach that tracks code behaviors, call stacks, and database usage. 

Using an automated refactoring platform, organizations can quickly convert monolithic code to microservices that fit within a Strangler Fig pattern approach for microservice modernization. They can help identify migration sequences and determine the scope of each microservice. Automated tools can even flag legacy services that should not be turned into microservices. 

Before starting a green-lighted modernization project, contact vFunction to request a demo and see how automation supports the Strangler Fig pattern.