The Strangler Fig Pattern

tagged with Developer Migrations

"This project needs a rebuild!" – How many times have we encountered this statement? A statement born of frustration, legacy code, and application complexity. Modernisation is needed, yet the path to achieving it can seem almost insurmountable.

For smaller projects, the concept of a rebuild might be straightforward. But when it comes to the large, monolithic giants, the idea of a complete overhaul is a massive undertaking, that can span months, or even years, and is riddled with risks at every turn.

There's also the potential loss of all the painstakingly written code and nuanced functionalities developed over many years. Those sudden realisations of "oh, I forgot it did that too!", causing missed deadlines, dropped functionality and inflated budgets.

In this article, we'll discuss a different path – using the Strangler Fig pattern.

A strategy for incrementally migrating large, complex projects over time without losing existing features.

Firstly, what are patterns?

In software development, patterns are like recipes in cooking. Just as a recipe provides a tested and structured approach for creating a dish, a pattern in software development is a proven solution to a common problem in a particular context.

They offer established solutions to recurring problems within a given scenario, serving not as direct code but as adaptable frameworks that act as a common vocabulary among developers.

The Strangler Fig Pattern

First coined by Martin Fowler, the Strangler Fig pattern describes an approach to upgrade legacy, monolithic systems. Migrating an old system to a new one, while preserving existing features.

Diagram of the strangler fig pattern: a facade intermediates between 'Legacy' and 'Modern' applications. 'Early Migration' shows the large 'Legacy' app and smaller 'Modern' app. In 'Later Migration,' the 'Legacy' shrinks as 'Modern' expands, indicating the gradual shift of functions.

 

The pattern facilitates the gradual transfer of features from the old to the new system. This ensures that the legacy application continues to operate, handling those long-forgotten features, while new functionalities are progressively integrated into the modern system.

A key component of this pattern is the implementation of a Facade or Proxy. This intermediary plays the role of managing incoming requests, directing them to the appropriate system, depending on where we are with the transition.

Implementing the Facade

In software development, a 'facade' is something that hides underlying complexity. In this instance it hides the fact that a user's experience is actually being served by 2 applications.

We can implement this facade by using a proxy server. Think of it as a digital postman - receiving a request from the user and, based on a set of predefined rules, determines the appropriate destination for that request.

A diagram depicting URL routing. A central '/tickets' URL splits into two paths: '/*' directing to a 'Legacy' system, and '/tickets/*' pointing to a 'Modern' system, illustrating a division of traffic based on URL patterns.

 

In this example we can see that the new application has been set up to serve the 'tickets' section.

When a user asks for the '/tickets/*' url, the content will be served from the new application, everything else will come from the legacy.

Cloud Based Proxy

In Azure a proxy can be implemented using services like Frontdoor and Application Gateway.

Frontdoor is an advanced traffic manager designed for efficient request routing.

Application Gateway can also be used and goes beyond URL routing with additional capabilities such as Load Balancing and SSL Termination.

Self Hosted - IIS

If you are hosting your site on a server using IIS, you can make use of the Application Request Routing (ARR) module for IIS.

This will allow you to control proxy routing rules in a similar way to managing traditional IIS Rewrite XML configurations.

Application Linking

Another technical facet of the Strangler Fig pattern is what we've termed 'Application Linking'.

This aspect tackles the challenge of elements in a website that cannot be easily categorised into discrete sections based solely on their URL.

An example web page layout with header and footer marked as 'Shared', indicating common content across pages. The central section is labelled 'Changes based on URL', suggesting this part of the page updates dynamically.

 

Consider a basic website, for instance. The main content in the middle changes, but there are consistent, global elements like Headers, Navigation, Footers, Site Alerts, and Banners, etc.

These elements are ubiquitous across the site and raise the question: how can we implement these so that they are centrally controlled and managed?

The initial step in this process involves selecting one of the applications as the 'source of truth' for this content - effectively, the master.

In our experience, it's been beneficial to use the legacy application as the 'source of truth', especially in the early stages of migration.

As the migration progresses and more of the application shifts, a crucial 'tipping point' is reached where control is transferred. We've typically observed this transition occurring near the end of the migration process.

Implementing this linking can be achieved through sharing data via a locked down API.

An alternative is using a fast, central data store, for example Redis.

Here you can use publish events in the legacy CMS to funnel updates into Redis. Consequently, whenever a page is loaded from the modern application, it pulls the relevant data from Redis, ensuring that all shared elements are up-to-date and consistent across the site.

When is it Useful?

 

Legacy Code: This pattern is particularly beneficial in scenarios involving applications mired in spaghetti code and extensive Technical Debt. It offers a strategic approach to cautiously explore and manage the associated risks and uncertainties.

Application Knowledge Gaps: When a codebase lacks sufficient documentation, or in situations where the original developers are no longer with the company, leaving gaps in application understanding.

Replatforming/Migration: when replatforming a website, or moving from a significantly older version of Umbraco to a newer one, helping to navigate the complexities and challenges inherent in such processes.

Challenges

The Strangler Fig pattern requires weighing the initial investment against the long-term benefits and is not without its challenges.

Each application brings its unique set of obstacles, and navigating these is a critical part of the process.

Some challenges when implementing this pattern include:

Infrastructure

A significant consideration when implementing the Strangler Fig pattern is the heightened infrastructure complexity it introduces. Instead of managing a single application, you now have two separate applications to oversee, along with the proxy layer.

It's essential to ensure that your team is equipped with the necessary skills to handle this complexity. This situation often calls for robust DevOps expertise, in addition to the regular development skills.

In this context, having solid Continuous Integration/Continuous Deployment (CI/CD) pipelines is more than just beneficial – it's a necessity.

Additionally, ensure a well-thought-out branching strategy is used, especially if Business As Usual (BAU) and maintenance activities are being carried out alongside the migration.

Two Backoffices

A prominent hurdle is the potential of ending up with two separate CMS back offices.

This issue could be a sticking point for some clients. However, if they're open to the process, there are strategies we can implement to alleviate the burden.

When segmenting the application, aim to focus on specific content areas that fall under a single core tree node at a time. This approach can make the transition more manageable.

Additionally, integrating helpful messaging and direct links to the new CMS within the old back office can be incredibly useful.

Other Key Technical Considerations

Other considerations will vary based on the specifics of your project and may include:

  • Migrating content & media
  • Site search
  • Sharing session state
  • User authentication & identity
  • Application linking connectivity & fault tolerance
  • Redirects, HTTP headers, server variables

Should I Use The Strangler Fig Pattern?

It's important to acknowledge that this pattern may not suit every application. We strongly advise against hastily adopting this approach for your next project without a thorough evaluation.

Consider the following aspects to determine if the Strangler Fig pattern is right for your project:

Application Knowledge: Does your company have comprehensive knowledge of the application's functionality? Lack of complete understanding might make the Strangler Fig pattern a viable option.

Code Complexity and Technical Debt: Is the legacy codebase overly complex, poorly documented, or burdened with technical debt? The Strangler Fig pattern can be an effective solution for addressing these issues.

Replatforming or Migration Needs: If your project involves replatforming or migration, the Strangler Fig pattern can be instrumental in mitigating risks while preserving essential features.

Team Expertise: Does your development team possess the necessary skills and experience to effectively implement the Strangler Fig pattern?

Client Buy-In: Is your client prepared for an incremental build approach and aware of the time it might take to realise the full benefits? Are they willing to accommodate compromises, such as managing two backoffices during the transition?

Budget Considerations: Does the project budget align with the incremental nature of the Strangler Fig pattern, considering it might not always be the most cost-effective approach?

Benefits of the Strangler Fig Pattern

When all factors – from budget and business to client and project needs align, the Strangler Fig Pattern is a compelling option, offering substantial benefits.

Incremental Iteration:

The approach can reduce the risks commonly associated with 'Big Bang' releases. Rather than a frantic push towards the end, development and content updates can be incrementally delivered, ensuring a smoother transition, minimising waste and maximising value.

Enhanced Control:

This pattern affords greater control over the entire migration process. It allows for management of individual sections and functionalities, enabling close monitoring of their progress. This granular control can lead to more predictable and successful delivery.

Preservation of Existing Functionality:

A gradual migration approach ensures that existing features and functionalities are maintained throughout the transition. This method minimises the risk of functionality loss.

Summary

The primary benefit of the Strangler Fig Pattern is the heightened confidence and control it imparts in the modernisation of large legacy applications, particularly in situations where the required effort is uncertain due to gaps in knowledge, legacy code complexities, or the daunting nature of the migration process.

This pattern's ability to maintain legacy features throughout the transition process is invaluable. It enables teams to focus more effectively on current tasks, spreading potential challenges over time rather than confronting them all at once.

If your project aligns with the requirements of this pattern, and you have a client who understands and supports this approach, along with a capable team, the Strangler Fig Pattern can be a tremendously effective tool for migrating legacy systems.