The technical landscape of legacy modernization presents its own set of hurdles. In this final installment of our three part series, we delve into overcoming technology challenges when applying the Strangler Fig pattern. We discuss establishing a robust testing loop, responsible testing practices, maturing CI/CD processes, and other crucial tech-centric considerations. The aim is to equip you with insights to tackle technical challenges and ensure a successful, smooth transition to a modern system. While part one introduced the Strangler Fig pattern and part two addressed people and process challenges, this part discusses the technical aspects of the modernization journey.
Establish a continuously improving test loop
Navigating the labyrinth of legacy systems can pose significant challenges, particularly when it comes to changes or reimplementations of critical functionalities that lack robust testing. An effective strategy to mitigate this risk and prevent regressions involves creating a black box: a short-lived suite of functional tests (my colleague Vanessa Towers calls them a parity suite) for a carefully chosen segment of the system.
A new implementation develops upon reliable verification of the legacy system's behavior. While it may look the same from an external perspective, the new implementation benefits from an internally enhanced design, ideally derived from test-driven principles. This strategy simultaneously ensures a suite of fast-running unit tests for regression and maintains the original functional tests.
Integrating these tests into a continuous integration pipeline can bolster the process further. Ratcheting on a set of key fitness functions, such as code coverage, cyclomatic complexity, the number of test assertions and Lack of Cohesion in Methods (LCOM4), provides timely, qualitative feedback on the system's health. Incorporating the practice of mutation testing offers valuable insights into the quality of the written tests, contributing to a disciplined and thorough process.
Functional tests are then applied to the new implementation, preserving the original functionality. After the test suite certifies the new implementation, it seamlessly replaces the original functionality, maintaining the end user's experience. Once validated, the ephemeral functional suite retains only the most valuable scenarios after a significant reduction. The graphic. on the left illustrates what the process looks like.
This systematic, risk-managed approach, enhanced by continuous integration and metric monitoring, can be replicated to modernize additional parts of the legacy system, optimizing the chances of successful transformation.
Test responsibly (not only) in production
"I don't always test my code, but when I do, I test in production," goes the infamous meme. However, testing (not just) in production is a powerful strategy that allows teams to validate changes and catch issues in the software's actual environment. It's crucial to approach testing in production responsibly to avoid disruptions and ensure a high-quality user experience. Several techniques enable safe and effective testing in production, particularly in the context of the Strangler Fig approach to system migration:
Feature flags (Toggles): Feature flags provide the flexibility needed to manage the exposure of new components based on their readiness and performance. By selectively enabling or disabling components in the live environment, teams can control risk while gathering real-world feedback.
Canary releases: Canary releases work well with incremental approaches like Strangler Fig. As one replaces each slice of the system, the new component can be initially exposed to a small subset of users, with exposure progressively increased as confidence grows.
Dark launches: Dark launching allows new components to be introduced and tested in the production environment without being visible to users, which aligns with the Strangler Fig approach by allowing new components to be tested with real production traffic before they fully replace the legacy system.
A/B testing: It's possible to use A/B testing to compare the performance and user experience of the legacy system and the new system. By directing some users to the new components and others to the legacy system, valuable feedback can inform the migration process.
Each technique provides a way to manage risk, gather real-world feedback and maintain a high-quality user experience throughout the migration process.
Improve the maturity of your CI/CD practices
Robust Continuous Integration/Continuous Deployment (CI/CD) practices are crucial in successfully implementing the Strangler Fig approach. CI/CD pipelines facilitate the automation of integrating changes, running tests and deploying to production. This automation is well-aligned with the incremental and iterative nature of the Strangler Fig strategy.
Frequent integrations: The Strangler Fig approach involves numerous small changes. CI practices support regular integration of these changes, helping detect and resolve integration issues promptly when they're less costly to fix.
Automated testing: CI pipelines automatically trigger various tests with every integration, ensuring each change is validated for functionality, performance and security — critical when different system parts are at various migration stages.
Consistent deployments: CD practices offer consistency and repeatability in the deployment process, reducing the chance of error, which is particularly important when managing legacy and new systems.
Rapid feedback: CI/CD provides quick feedback on every change, which is essential for the iterative nature of the Strangler Fig approach. This allows teams to respond to issues quickly, make improvements and deliver better quality software.
Version control: Well-established CI/CD practices involve strong version control, ensuring all changes are trackable. This is crucial when managing the coexistence of old and new systems.
Rollbacks: If issues arise, well-structured CI/CD pipelines allow for quick rollbacks, minimizing disruption to users and the business.
Adopting robust CI/CD practices isn't just a technical requirement but also a cultural one. It necessitates a commitment to frequent, incremental changes, shared responsibility for quality and reliability, as well as an investment in automation and tooling. This level of sophistication in CI/CD practices helps ensure a smooth and successful Strangler Fig migration.
Embrace the need for data synchronization
Running both old and new systems side by side, a characteristic of the Strangler Fig approach, necessitates data synchronization, which presents challenges such as ensuring data consistency and integrity, managing performance impacts and navigating the complexity of transforming data formats or handling different database technologies.
To effectively manage these challenges, robust data synchronization tools are needed, along with failover and recovery mechanisms, performance optimization, monitoring and alerting systems, and thorough testing.
However, minimizing the need for two-way data synchronization is crucial, which can be complex and error-prone, and is achieved by carefully choosing thin-slice use cases for migration, aiming for those that are relatively independent and self-contained. This strategy allows for predominantly unidirectional data flow — from the old system to the new system — avoiding the need for reflected changes in the new system.
For instance, if you're migrating an e-commerce platform and you start with the product review functionality, all new reviews could be written directly to the new system, while the old system is updated to read reviews from the new system. This approach simplifies synchronization, reduces potential conflicts, and requires careful planning and a comprehensive understanding of the system and its data dependencies.
As the migration progresses and more functionality moves to the new system, the need for synchronization will gradually decrease until the old system can be fully decommissioned. This holistic approach to data synchronization is key to a successful migration.
Ensure a robust observability apparatus is in place
The Strangler Fig approach to system migration is fundamentally an incremental process involving the gradual replacement of parts of a system while the whole continues to function. This approach requires that the teams involved have a deep and detailed understanding of the system at all stages of the process and where having a world-class observability apparatus comes into play.
Observability, in the context of system migration, means having visibility into how the system's components interact and perform, both individually and collectively. This observability includes metrics (quantitative data like response times or error rates), logs (records of events that have occurred within the system), and traces (information about the path that a transaction or workflow takes through the system).
An effective observability apparatus provides several critical capabilities:
Error detection and diagnosis: It allows teams to quickly detect and diagnose issues, which is especially important when introducing new components that must coexist with legacy ones..
Performance monitoring: It gives teams insight into the performance of both the old and new components, helping them ensure that the new system can meet or exceed the performance of the old system.
User experience monitoring: Observability tools can provide valuable insights into how users interact with the system, helping teams understand the impact of changes on the user experience.
Data-driven decision making: Observability provides the data needed to make informed decisions about the migration process, such as prioritizing which components to replace next.
Confidence in deployment: With high observability, teams can confidently deploy new components, knowing they can quickly detect and address any issues that arise.
Having a world-class observability apparatus is key to successfully pulling off a migration using the Strangler Fig approach. It allows teams to closely monitor the system's health, performance and usage as they gradually replace its components, providing the insights and confidence needed to manage the process effectively.
Conclusion
As we journey through the dense undergrowth of legacy systems towards the clear canopy of technological innovation, the Strangler Fig approach shines a light on a pragmatic and effective path. It allows organizations to delicately unfurl the tendrils of modernization, weaving them into the old system incrementally, thereby reducing risk and minimizing disruption.
The journey, though, is not without its challenges. It requires the navigator to master several guiding principles and practices. Choosing the "just right" thin slices sets the pace of the journey, while the ability to embrace and manage scope changes defines its flexibility. The selection of optimal granularity for production releases further refines the path, adding precision to each step.
Alongside these strategic decisions, operational considerations also come into play. Testing responsibly in production, maturing CI/CD practices, and embracing the need for data synchronization act as safeguards, ensuring the journey proceeds smoothly even as the landscape changes.
Above all, the journey through the Strangler Fig approach requires constant observation and communication. Establishing a robust observability apparatus provides the vision to navigate through complex terrains, and proactive communication and change management practices ensure the entire team marches in unison, aligned towards the shared goal.
In conclusion, while the Strangler Fig pattern presents its unique set of challenges, it offers a manageable approach to system modernization. With the right strategies and tools, it's a path that guides organizations safely and surely from the depths of legacy systems into the bright daylight of technological advancement.