What’s Strangler Fig pattern and how it can help to refactor legacy systems

WINW > Software Development > Design Patterns > What’s Strangler Fig pattern and how it can help to refactor legacy systems

The Strangler Fig pattern, often just called the Strangler Pattern, is a design pattern used in software development to incrementally refactor a monolithic application into microservices or a more modular architecture. It’s particularly useful when dealing with large, complex, and business-critical legacy systems where a complete rewrite is too risky or impractical.

The name comes from the strangler fig tree found in tropical forests. This fig tree starts as a small vine that grows around a host tree. Over time, the fig tree grows larger, its roots and branches eventually encompassing and “strangling” the host tree, which eventually dies and decays, leaving the fig tree standing in its place.

How it Applies to Software:

In the software context, the “host tree” is your monolithic legacy application. The “strangler fig” is the new, modern services you’re building. Instead of trying to rip out the entire old system at once (which is incredibly risky), you:

  1. Identify a specific, small piece of functionality within the monolith that can be extracted and rewritten as a separate, new service (a “microservice”).
  2. Build the new service alongside the existing monolith.
  3. Reroute traffic/requests for that specific functionality from the monolith to the new service. This is often done using a facade or a proxy layer that sits in front of both the monolith and the new services.
  4. Gradually extract more functionality into new services, one by one, repeating the process.
  5. Eventually, the monolith shrinks as more and more functionality is migrated out. The old code paths become less and less used, eventually becoming obsolete and ready for removal.

Key Principles and Components:

  • Incremental Migration: The core idea is small, manageable steps, reducing risk.
  • Coexistence: The new services and the old monolith operate simultaneously for a period.
  • Facade/Proxy Layer: A crucial component that intercepts requests and directs them to either the old monolith or the new service, based on the functionality being requested. This is often an API Gateway, a reverse proxy, or a custom routing layer.
  • Backward Compatibility: New services must maintain compatibility with existing systems that interact with the monolith.
  • Observability: Robust monitoring and logging are essential to understand traffic flow and identify issues during the migration.
  • Testability: Each new service should be independently testable.

When to Use the Strangler Pattern:

  • Large, complex legacy monoliths: When a complete rewrite is too risky, costly, or time-consuming.
  • High business criticality: When downtime or errors are unacceptable.
  • Need for incremental modernization: When you want to gradually adopt new technologies or architectures.
  • Desire for independent deployments: When you want to deploy parts of your application without affecting the whole.
  • Team learning and adoption: Allows teams to learn about new architectures (like microservices) in a controlled manner.

Benefits:

  • Reduced Risk: Lowers the risk of a “big bang” rewrite failure.
  • Improved Agility: Enables faster development and deployment of new features once functionality is moved to new services.
  • Better Maintainability: New services are smaller, more focused, and easier to maintain.
  • Technology Adoption: Allows for the introduction of new technologies without rebuilding everything.
  • Continuous Value Delivery: New features can be delivered even while the migration is underway.
  • Scalability: New services can be scaled independently.

Challenges and Considerations:

  • Routing Complexity: Managing the routing layer can become complex as more services are introduced.
  • Data Migration: Deciding how to split and migrate data can be challenging. Often, data is replicated or eventually consistent.
  • Duplication: Some temporary duplication of code or data might occur during the transition.
  • Operational Overhead: Managing two systems (monolith and microservices) simultaneously can increase operational complexity.
  • Team Coordination: Requires good communication and coordination between teams working on different parts of the system.
  • Identifying Boundaries: Deciding where to draw the lines for new services can be difficult.

Example Scenario:

Imagine a large e-commerce monolith. You might start by extracting the “order processing” functionality into a new microservice.

  1. Initial State: All order processing logic is within the monolith.
  2. New Service Creation: A new “Order Service” is built using modern technologies.
  3. Routing Layer: An API Gateway is put in front of the monolith. When a request for /orders comes in, the gateway initially routes it to the monolith.
  4. Strangling: You update the API Gateway to route /orders requests to the new “Order Service” instead of the monolith.
  5. Iteration: You then move “product catalog” to another service, then “user authentication,” and so on.

Over time, the monolith becomes smaller and smaller, eventually containing only residual functionality or perhaps being completely decommissioned.

In essence, the Strangler Pattern is a pragmatic and effective strategy for modernizing legacy systems, allowing organizations to evolve their architecture incrementally and reduce the inherent risks of large-scale transformations.

Leave a Reply