Picture a scenario all too familiar in software engineering: a legacy application, once cutting-edge, now a relic of yesterday’s technology. While the product remains vital to the business, its relevance is fading due to an outdated user experience and lack of extensibility. The application’s fragile state and towering technical debt have given the engineering team unrelenting anxiety. Everyone, including leadership, wants it replaced, but the undertaking seems insurmountable. It is a relentless struggle to evolve, one I have witnessed countless times in my years of consulting.
Fortunately, two distinct, yet complementary engineering paradigms can provide a path forward:
- The Strangler Fig Pattern is an iterative approach to modernization that allows responsibilities to be subtly transferred away from an outgoing system in stages.
- Micro frontends represent an architectural design pattern that divides a frontend into smaller, self-contained, and independently deployable units.
While seemingly unrelated on the surface, when paired together, these concepts forge a unique and powerful transformation strategy that can deliver a modernized product to market in a fraction of the time. Meanwhile, organizations are able to defer costs, maintain stability, and guard against uncertainty. Embraced by industry titans such as Spotify and Upwork, this winning combination of ideas promises to revolutionize how digital products evolve and thrive in a rapidly changing landscape.
The Big Bang
The often-instinctive approach to modernization, dubbed the “big bang,” involves a complete rewrite of the entire application from the ground up. A push to upgrade underlying technology can make pursuing such a strategy particularly compelling. While this may seem like the right answer and certainly sets the stage for an exciting product launch, it has proven to carry substantial drawbacks and risks:
- An all-at-once replacement is expensive, and the return on investment is distant. Since fixes and enhancements to the existing application must typically continue in parallel to satisfy ongoing product demand, this often means turning to an outside vendor or taking on additional resources. Such an endeavor demands a great deal of runway.
- A full rebuild takes an extensive amount of time and customers are often unwilling to wait. Potential revenue loss looms as users gravitate to more alluring and innovative alternatives.
- Product failure is a real possibility. Agile principles have taught us that we need to get software in the hands of users early and often. In the case of an overhaul, however, you can’t go to production until you have reached full feature parity with the existing application. Going live with unvetted changes at this scale could mean disaster, including widespread bugs, system vulnerabilities, user dissatisfaction, and compromised business operations.
Throughout the digital era, there have been many notable cases that underscore the potential impact of the big-bang misstep:
- In 1998, Netscape decided to rewrite its browser code from scratch, which took three years. During this time, Internet Explorer released two new versions, lending to Netscape’s devastating loss of market share.
- In 2009, MySpace decided to rewrite their entire website in an attempt to compete with Facebook. The project was plagued with issues and delays, and the resulting site was widely criticized for its design and functionality. The failed initiative is often cited as a key factor in MySpace’s decline.
- In 2013, Research In Motion (RIM) attempted to rewrite its operating system, BlackBerry, to compete with iOS and Android. However, the decision led to significant delays, backward compatibility issues, and user alienation. Ultimately, it contributed to BlackBerry’s demise in the smartphone market.
Strangler Fig Pattern
Undoubtedly, an agile approach would be far more favorable. This is where the Strangler Fig Pattern aligns. Coined by Martin Fowler, this term finds its metaphorical roots in the unique lifecycle of the strangler fig tree. Initially emerging as a vine, the strangler fig grows to envelop an older, more established tree, intricately weaving its way around the host until it eventually overtakes and replaces it entirely.
To put this in real terms, our objective should be to facilitate a gradual transition where the existing system and its eventual replacement are able to harmoniously coexist side-by-side for an interim period. The two infrastructures must operate concurrently in a way that is entirely invisible to the user without causing disruption or compromising functionality. Once coexistence is achieved, the outgoing system is then decommissioned in stages as its responsibilities are gradually transferred to its modern counterpart. This iterative process continues until all legacy components and services are phased out, and the original system is eliminated altogether.
When implemented effectively, the Strangler Fig Pattern significantly mitigates the risks associated with large-scale replacements. Instead of waiting for a complete system overhaul, new components are integrated and released independently as they are developed. These incremental updates can be deployed swiftly and regularly, while the rest of the application as a whole continues to function as normal. The flexibility inherent in this approach accelerates value delivery and empowers organizations to prioritize and reimplement features selectively based on budget constraints, resource availability, and other business priorities.
Breaking up the Monolith
The essence of the Strangler Fig Pattern is to incrementally build a new system around the edges of the old and replace functionality piece by piece. While this does not require a system to be fully distributed, it does require a high degree of modularity.
The first step is to identify or establish technical boundaries within the existing application, commonly referred to as “seams.” Seams act as delineation points of modularity, facilitating the subsequent decoupling and decomposition of the application into smaller, independent, and replaceable units. Creating these lines of separation is a two-dimensional puzzle, requiring both horizontal and vertical considerations:
- In the horizontal context, applications can be segmented and systematically replaced by layers (presentation layer, service layer, data access layer, etc.). Typically, an intermediary facade is positioned between the affected layers to represent each functional entry point. This allows incremental replacement behind the facade with relatively low risk.
- Vertical separation involves segregating components and services based on their functionalities. Each vertical slice represents a self-contained, highly cohesive, and independently deployable unit that encompasses all layers and serves a specific business capability. This makes vertical separation more advantageous in the context of the Strangler Fig Pattern as it provides a finer level of decomposition. We are able to deliver end-to-end functionality with each increment while selectively replacing only the parts of each layer that are necessary. This offers greater flexibility in determining the scope of each increment and in prioritizing which pieces of the system to replace.
For a monolithic backend, vertical segmentation often involves transitioning to a microservices architecture. Microservices streamline the incremental replacement of services and facilitate a smooth transition without disrupting the existing system.
For the frontend, however, decomposition is not so straightforward. Frontends tend to be tightly coupled with complex interdependencies, making it very challenging to create these seams. This is why many engineers find the Strangler Fig Pattern applicable only to backend migrations. Consequently, frontends are often left in their holistic state and replaced as one unit. Thankfully, there is an answer hidden in a design pattern most commonly associated with scalability. This is where micro frontends take center stage.
Micro Frontends
Micro Frontend architecture (or MFE for short) is a design pattern and set of principles that allows engineering teams to independently develop, test, deploy, and scale fragments of a UI as decoupled units. These units (called micro frontends) are then reassembled (usually at runtime) into one cohesive user interface.
MFE gained popularity after the explosive adoption of microservices as a way to extend that same level of modularity to the frontend. In many ways, micro frontends and microservices are mirror images of each other:
- Both break a monolithic architecture down into small, independently deployable units, allowing for modular development, independent scalability, and team autonomy.
- Both promote continuous delivery and facilitate faster development cycles by allowing components to be released individually without impacting the entire system.
- Both promote technology agnosticism by allowing technology decisions to be made independently for each unit without compatibility issues. This is a crucial ingredient when applying the Strangler Fig Pattern.
By allowing components to originate from independent deployments, and further permitting competing technologies (such as React or Angular) to coexist within a single interface, MFE provides the clean mechanism we need to achieve full feature parity from the onset. While some features or views reside in the new codebase, others can be subtly sourced from its predecessor. With a little bit of styling to ensure consistency, this experience is completely seamless to users.
We are then able to incrementally replace the frontend in thin, vertical slices without impacting the rest of the application. As features are reimplemented in the new codebase and their former versions are decommissioned, an indirection layer intelligently routes requests and delivers content from the appropriate location.
MFE Adoption and Use
While MFE does offer a means for us to apply the Strangler Fig Pattern on the frontend, this is not its predominant use case.
- MFE is particularly well-suited for teams working on large-scale applications. This architecture gives team autonomy by design, allowing them to develop, deploy, and scale their respective parts of the application independently, without the complexities and chaos of a shared codebase.
- MFE is also ideal for organizations seeking to integrate a fragmented suite of products and tools. Instead of having to juggle multiple applications, users can enjoy a unified and seamless experience with all applications consolidated in one interface. Organizations are then able to extend their product lines simply by incorporating additional micro frontends into the ecosystem.
Though still unknown to many, the concept of micro frontends is not uncharted territory. MFE has been adopted for one reason or another by many major companies such as Spotify, Netflix, Ikea, American Express, Upwork, Capital One, OpenTable, PayPal, HubSpot, SoundCloud, Hello Fresh, and Starbucks. Personally, I have spearheaded more than a handful of micro frontend implementations, including a few that fall outside the realm of modernization.
All of this is not to say that MFE is right for everyone. While some herald it as “the future of frontends,” there are also critics who find it burdensome. Just like anything else we work with, MFE comes with its share of drawbacks, including complexity, overhead, and cross-cutting concerns.
One aspect to consider when leveraging MFE for migrations is that it doesn’t necessarily have to be a permanent fixture. If all features are reimplemented and their outdated versions are retired, the micro frontend overhead can be lifted. On the other hand, the team might decide by then that it is time to embark on the next generation of technology. MFE allows modernization to become a continuous practice rather than a reactionary hardship, indefinitely preventing the system from returning to an outdated state.
Implementing MFE
Various technologies can be used to orchestrate the loading and embedding of micro frontends. Often, these technologies also handle routing, state management, and communication between the micro frontends. There are multiple implementation models and an array of frameworks and tools, each with its own unique take on solving the problem.
The biggest differentiator among the various options is how and where rendering and composition take place. Client-side composition tends to be more common, with implementation models such as dynamic module loading, iframes, Web Components, and Module Federation. Composition can also be handled at the server level or provided by a CDN. While there are many out-of-the-box products such as Single-Spa and Luigi, it is also common for teams to roll their own custom solution or implement a hybrid of multiple tools.
It’s important to remember that MFE is a design pattern, not a prescription. It defines the ‘what’, not the ‘how’. As with any transformative endeavor, careful consideration of all the options is paramount. In the context of migrations, not all solutions are created equal. Some options may work flawlessly in greenfield scenarios, but they do not stand up well to the challenges of retrofitting existing code. Finding the right fit is key, and unfortunately, there is no one-size-fits-all.
First and foremost, we must be able to integrate with minimal modification to the old code. Given the complexities of componentization, runtime isolation, state management, dependency management, and other critical factors, some solutions require changes that can inadvertently cascade far and wide. Not only is time spent converting code that will soon be replaced wasteful, but it also presents significant risk. If the code lacks adequate testing, that risk is even greater.
Bringing It All Together
The first time I inadvertently combined the Strangler Fig Pattern with Micro Frontend architecture was purely by happenstance. It was a fairly basic iframe implementation on a transformation carried out years before I became acquainted with terminology for either concept. While my techniques have undoubtedly evolved over time, the fundamentals have remained a mainstay of my practice.
Recently, I consulted for a client specializing in fundraising tools for large non-profit entities. My team was tasked with building the next-generation version of their robust platform. In addition to achieving full feature parity, the replacement product needed to offer a revolutionary set of new features promising to shake up the industry. Not only did our client require a swift product launch, but they also aimed to unveil it at a big industry conference in less than a year. We needed to focus the limited time we had on knocking the new features out of the park.
Determined to meet the tight deadline, we turned to the Strangler Fig Pattern and Micro Frontend architecture. The end result was a beautiful new React application that seamlessly served restyled instances of the legacy features built in an early version of Vue, right alongside the new functionality in one cohesive customer experience, unbeknownst to the user. The new product immediately witnessed a 45% growth in revenue over its predecessor. After the release, our client’s engineering team was able to gradually begin replacing the remaining legacy functionality in small increments as new user stories were introduced in those feature areas. Our approach to modernization in-place deferred cost, reduced risk, and enabled our client to quickly provide value to their customers. This is one example of many.
The journey from legacy to modern is rife with challenges and opportunities. By embracing the Strangler Fig Pattern and harnessing the power of Micro Frontend architecture, organizations can get innovation into the hands of users without all the setbacks. Together, these strategies enable your team to navigate iterative transformation and face the ever-changing technological landscapes with agility and confidence.
ABOUT THE AUTHOR
John Lawrimore is a Principal at Dialexa, an IBM company. John carries nearly 20 years of digital product engineering experience with areas of specialization that include modern web development, usability, solution architecture, test-driven development, and Agile methodologies. As a seasoned consultant, trainer, and former professor, John aims to cultivate high-performing teams, help build innovative solutions, and maximize stakeholder outcomes.
Connect with John on LinkedIn