Back in its days, Zend Framework 1 used to be one of the most popular PHP frameworks around. Even now, 8 years later, there are numerous working applications built on top of it. Because ZF1 has reached it's EOL and is not supported anymore, companies and development teams are considering upgrading it to something more modern. While the default choice is often to migrate ZF1 application to Zend Framework 2 (or 3), there's a good alternative - Zend Expressive. Expressive is much smaller, better suiting modern, API-centric applications. It promotes separating business logic from the legacy code, and I would argue that it is easier to master than ZF3.
This is what we did in my company, with good success. With relatively small effort, in 2-3 years we've been able to reduce our legacy code base to only 18% of total 300k lines of code (meaning that only 18% is now dependent on old ZF1).
Because from time to time I'm getting questions about the migration, I'd to blog about it. In this post, I will give a basic introduction, and later on, I'll show concrete code examples.
Is it for you?
Before considering an actual upgrade, you have to consider the pros and cons. Depending on what you have in your repository, it may be a long and difficult process - even if you plan it properly in advance.
When does it make sense to upgrade?
- You don't plan to phase out your application anytime soon. This should be obvious - if you don't plan to continue supporting your app, you should not invest your time and money in it anymore.
- The application cannot be replaced by third-party software. If the application doesn't solve the core needs of your business, then you should consider finding an alternative already existing on the market. For example, when working on an enterprise-grade project, there's no point in building your own authentication service - there are plenty available, like Amazon Cognito. In this case, it is better to put your team's energy into integrating such service, instead of doing an upgrade. Even if your application is not a commodity available on the market, but it still doesn't solve the core problem of your business, consider outsourcing it.
- Application is medium to large in size and is not tightly coupled with any other system. If your app is small and standalone, it may be cheaper to rewrite it from scratch.
- It is a living project, often modified. Developers tend to dislike working with a legacy code base. If you stay for too long on the old framework, you may end up in a situation when attracting new talent will be challenging. On the other hand, if your app does not change much, why spend time on modernizing it?
If - after reading the above list - you are unsure whether an upgrade is a good decision, then probably you should not do it. Consider alternatives: replacing your application with a solution available on the market or outsourcing it. There are also technical solutions, like erecting new, modern application next to the old one and separating the traffic using web server (or load balancer, say if you're using AWS Application Load Balancer), based on the requested path.
So, you are not scared by the previous section and still want to move on and dust off your old ZF1 application. That's great!
Before moving forward, let's set up some rules and discuss the approach:
- You do not want to upgrade everything at once. There are probably parts of your system that work just fine and do not change often. Don't refactor the whole application just for the sake of having a modern codebase. Avoid temptation and make sure your team works on something that brings business value.
- At the same time, you will want to gradually improve the code quality, taking advantage of modern patterns like Service Containers. You will be writing new code that is separated from the framework, using DDD or Clean Code guidelines. You should be able to use this new services both in old and new codebase.
- You want to share configuration and utility classes (such as view helpers) between modern and legacy code, to avoid duplication.
- Functional tests are your best friend in the migration process. If your old application doesn't have a good test suite, now it may be good time to start building it.
How to get there with ease? The solution I will present is to wrap the legacy code with a Zend Expressive middleware. This way, every request will reach Expressive application first. If it cannot serve the request (there's no defined route for a given URL), the old Zend_Application is bootstrapped and handles the request. While this may be enough for you, the next step will be to integrate both applications by sharing ServiceManager instance between them. Finally, I will show how to handle other typical problems like sharing error handling, configuration and view helpers.
In the following articles, I will show concrete examples of how to work on this integration from the coding perspective. I will be also publishing example application on GitHub, so that you will be able to see it in action.