Nearly half of the projects we help upgrade have tried the upgrade before on their own. They've introduced the infamous "strangle pattern". It's a way to upgrade a project separating one part of the codebase from the rest at a time.
Those companies reach us because while the strangle pattern is great in theory, it rather strangles the project in practice. They're unable to move, they use now 2 frameworks instead of one and the team has to work with complexity squared.
Today we'd like to share why it's a terrible choice and what upgrade strategy to take instead.
In programming, the strangler pattern is an architectural pattern that involves wrapping old code, with the intent of redirecting it to newer code or to log uses of the old code (taken from Wikipedia).
How does it look in practice?
Let's say we have an old CakePHP, CodeIgniter, Yii, or plain PHP project and you want to upgrade to Symfony or Laravel. You start by isolating part of the project, e.g. invoicing, and wrap it with Symfony or Laravel controller.
In practice, it can look something like:
That way, we'll have soon the full invoicing in Symfony or Laravel, right?
No, in practice this is a terrible idea. Why?
What is necessary to introduce a single Symfony/Laravel controller into an old project?
To set up a single invoicing controller, we have to set up the whole Symfony/Laravel HTTP, DI, and Routing layers. This could be months of work without showing any value to the customer.
Have you heard of The Mythical Man-Month book? Its central theme is that adding manpower to a software project that is behind schedule delays it even longer.
Same way as adding a parallel framework
will make upgrading the project even harder.
If we could come to a project in a moment before they put 1 year into a strangle pattern upgrade, we could save them a lot of time and money. It usually takes 3-6 months just to untangle the project to its original state.
Let's say we finished the upgrade of invoicing module to the Symfony/Laravel framework. Now we've done almost the full framework migration path, but there are still 3 modules we have to upgrade. We have just quadrupled the upgrade costs. In our experience, there are around 15-30 modules in such PHP projects.
What is the result?
Instead of chopping off the project and doubling everything, we should focus on the smallest steps possible to make project upgrade a success. We use the pattern refactoring approach.
What does pattern refactoring look like? The gist of this approach is to refactor single pattern in the whole project at a time. That means we always have one framework responsible for one part. There are never 2 frameworks handling the same area e.g. controllers, like in the strangle pattern.
That way we have always one framework responsible for one part of the project.
We have been using this approach since one of our first upgrades in 2017. We only improve the CLI tooling and automation around it. If we discover a new pattern, we add it to the Rector/tools and use it instantly in the next project.
This way, you can migrate the whole project to Laravel in under a year - see this Rector case study.
The pattern refactoring is not just for very complex legacy-framework to Symfony/Laravel migrations. They're also suitable for long framework upgrades like Symfony 2.8 to 7.2. Once you learn it, you can re-use and benefit from it in many projects.
Happy coding!