Refactoring Legacy Code with the Strangler Fig Pattern

There are strategies for reducing the size and responsibilities of large objects. Here’s one that worked for us at Shopify, an all-in-one commerce platform supporting over 1M merchants across the globe.

Adrianna Chang
15 min readadvanced
--
View Original

Overview

The article discusses the Strangler Fig Pattern as a strategy for refactoring legacy code, specifically focusing on the Shop model within Shopify's Ruby on Rails codebase. It outlines a seven-step process to incrementally extract and replace complex functionalities, ensuring minimal disruption and improved code quality.

What You'll Learn

1

How to apply the Strangler Fig Pattern for incremental code refactoring

2

Why defining clear interfaces is crucial for successful refactoring

3

How to backfill data from legacy systems to new data sources

Prerequisites & Requirements

  • Understanding of object-oriented programming concepts
  • Familiarity with Ruby on Rails framework

Key Questions Answered

What is the Strangler Fig Pattern and how is it applied?
The Strangler Fig Pattern is an incremental approach to refactoring legacy systems. It allows developers to gradually replace old code with new implementations while maintaining functionality. This method minimizes risks associated with large-scale changes by ensuring that the old system remains operational until the new system is fully validated.
How can I determine where to start refactoring legacy code?
Using code metric tools like Flog can help identify areas of code that require refactoring. Flog scores code based on assignments, branches, and calls, allowing teams to pinpoint disordered sections, such as the store settings in the Shop model, which can be a starting point for refactoring.
What are the steps involved in the Strangler Fig Pattern?
The Strangler Fig Pattern involves seven steps: defining an interface for the new system, changing calls to the old system, creating a new data source, implementing writers for the new model, backfilling the new data source, updating reader methods, and finally stopping writes to the old source and deleting legacy code.
What challenges might arise when refactoring a large class like Shop?
Refactoring a large class can introduce risks such as incorrect assumptions about where to move features and potential downtime. It is crucial to ensure that the extraction process is reversible and that the application remains functional throughout the refactoring process.

Technologies & Tools

Some links below are affiliate links. We may earn a commission if you make a purchase.

Key Actionable Insights

1
Start by defining clear interfaces for new components when refactoring legacy code.
This practice ensures that the new system can be tested and validated independently, reducing the risk of introducing bugs during the transition.
2
Utilize code metric tools like Flog to identify problematic areas in your codebase.
By pinpointing sections of code that require attention, you can prioritize refactoring efforts and improve overall code quality.
3
Implement a backfill strategy to migrate existing data to new data sources.
This ensures that your new system has all necessary data while maintaining consistency and integrity during the transition.

Common Pitfalls

1
Failing to define clear boundaries between components can lead to increased complexity and confusion.
Without well-defined boundaries, developers may struggle to understand the responsibilities of different parts of the code, leading to potential bugs and maintenance challenges.
2
Not ensuring that the new system is fully operational before removing the old system.
If the new implementation is not thoroughly tested and validated, it could lead to downtime or loss of functionality, impacting users and business operations.

Related Concepts

Refactoring Techniques
Component-based Architecture
Code Quality Metrics