The State of PHP MVC Frameworks in 2017 (Laravel, Symfony, CodeIgniter, CakePHP, Zend)
A simple question prompted me to sit down and write this follow up to my article from about a year ago.
Q: Any thoughts about where things are today? (2/24/2017)
A: “I’d say it’s pretty much down to Laravel and Symfony at this point; when it comes to PHP frameworks. I don’t feel that there is any specific value to using CakePHP, Zend, CodeIgniter, Yii, etc. if you are starting a new project.
Only if you already know those frameworks or have developers that are used to working with them, I could see a reason to use them.
When real development starts you have to be able to find tools, plugins, answers to common problems. And with Laravel and Symfony communities and constant development of new “modules” or features, you never feel like you’re left behind. Laracasts alone (even if you don’t develop in Laravel) are simply fantastic.
Whether it’s integration with services like iron.io or other SaaS providers, support for a wide variety of data-sources, local dev env like “Homestead”, these frameworks and supporting modules are much more forward driven.
Complimented by Lumen for quick API development Laravel really shines as a great approach to rapid application development and prototyping nowadays. Not to say that it’s somehow limited [when it comes to building] larger applications.
Generally speaking, however, we’re definitely seeing a shift towards a container-based architecture, where MVC plays a much lesser role. It’s all about microservices, orchestration and building apps as “functions” (i.e. AWS Lambda and similar services). Perhaps it’s time to brush up on your Node/JS and GoLang skills :)”
Although I felt generally happy with this answer, I couldn’t help thinking that elaborating on some of these points and taking a fresh look at where things are would be a good idea.
Before I jump into the strange topics like “GoLang”, let’s actually take a step back and glance at the trends in 2017, in the PHP MVC Frameworks World.
I would say that the trends we’ve observed in the past are holding up. Laravel is still pushing forward, while most everyone else is falling behind. There is a little uptick in Symfony popularity, probably due to the much awaited release of Symfony 3.
(I have tried more specific searches for comparison such as “CakePHP 3”, or “ZF2”, however those did not produce statistically significant trends).
This year I’ve included CodeIgniter because it is very popular, as evident. I received a number of questions about CodeIgniter and my thoughts on where it stands in the PHP MVC community…
Well to keep it short, CI is still out of the competition because it’s not a true MVC framework. I don’t know what to call it other than an organized collection of POPO’s …
Let’s just take this quote directly from their manual:
CodeIgniter has a fairly loose approach to MVC since Models are not required. If you don’t need the added separation, or find that maintaining models requires more complexity than you want, you can ignore them and build your application minimally using Controllers and Views.
When it comes to building a framework I simply disagree with this approach. Perhaps it’s a decent boilerplate, hence CodeIgniter’s popularity, however there must be some discipline enforced by the framework, otherwise the eventual product winds up being a mess of spaghetti code, wrapped into some sort of a “pattern”.
Moving on, Symfony 3 brought us some decent improvements in developer experience, dependency injection and a number of other features. Like many PHP counterparts it now offers a micro-framework. ZF3, comparatively, delivered a set of improvements, like support for PHP7 (finally) and even a micro-framework of its own… but like their manual says:
For Zend Framework 2 MVC users, the differences are subtle…
I was really hoping that they would say that the differences are dramatic, that there was some great architectural improvement, wonderful new modules that help you develop things in a modern way. Alas, for the most part ZF3 remains pretty similar to ZF2.
Long story short
Here’s how I see the world of PHP frameworks today:
- Symfony or Laravel, depending on your needs
- The rest
Hands down, Laravel stole the show. The amount of information available, Laracasts, world wide developer talent, simple pattern implementations, integrated testing toolsets, active record implementation in the form of Eloquent, lightweight version in Lumen, local development using Homestead (Vagrant) make this framework really stand out for new and seasoned developers.
However Eloquent models can get unruly and rather large in size, too many Laravel services may be created (not to be confused with microservices) and people start thinking about Repository pattern implementation where it doesn’t belong. Thus a Monolith is born.
If you are not comfortable with the active record pattern and need the added flexibility of Repositories, or perhaps you’re seeing too many anonymous functions for your liking, then use Symfony + Doctrine.
Do I consider Symfony a gateway to monolithic applications? To some degree, yes. However, it is probably the most elegant one.
Overall, I would not call it a drastic change from the last year. Still, we need to take a look at the bigger picture: a properly designed application goes beyond just MVC; it’s about infrastructure, deployment pipeline, decoupled architecture. All of these can be achieved in an MVC stack, but one needs to be extra mindful to avoid the Monolith.
Advent of Microservices
Earlier I’ve alluded to the rise of the microservices and the need to brush up on GoLang or Node skills.
Indeed, even in the PHP MVC article it would be silly not to mention a clearly happening move towards microservice oriented architecture (MOA); and it’s gaining momentum like you wouldn’t believe it.
While the two concepts are not mutually exclusive there’s no reason trying to find parallels between the two, as they really do represent different, albeit intersecting philosophies.
As an example, putting your MVC app in one container and MySQL in another and then linking them together, doesn’t necessarily represent a proper MOA.
This is certainly a better approach, in fact much better, than trying to install MAMP, XAMPP or whatever other clutter you need in order to get your local machine to serve an application.
Additionally, it may solve some issues like ease of running a local environment across different platforms (developers) and perhaps deployment strategy, in some cases, but you are stuck with an MVC Monolith in your app layer/container.
Destruction of the Monolith
This “destruction” is what microservices are all about.
While MVC addresses your code structure and organization by providing a solid approach to the separation of concerns, this concept is extended even further by the containers/services/MOA.
Instead of just separating your views from your models, you are now separating each “chunk” or logical unit of your application into an individual service, designed to properly handle its own responsibilities.
If your MVC app has a “Search” controller, action, and relevant Model methods, then we already have an example of a monolithic application.
In contrast, using MOA approach, we’d have a service for each one of those processing units. As an example:
- Router Service
- Request Service
- Query Service
- DataSource Service
- Response Service
Wait, but aren’t all those “services” are just a part of an MVC stack. Well, yes, exactly. They are the building blocks of our Monolith.
With MOA each service runs within its own environment, and as developers, but more so as architects we are free to design the best approach to solving a specific need.
As an example if I were to write an Image Processing Service within a Laravel environment, I’d probably be using something like PHP-GD2 extension, which may not be the most efficient way to process images. A C++ service that handles my needs of image processing, may be a lot faster and definitely more robust at scale. To elaborate even more we could now take the output of the Image Processing Service and send it off to DataStore Service, CloudStorage Service and Queue Email Service.
Solving this same challenge with a bunch of cron jobs and possibly a couple of separate MVC apps and custom scripts is how we did things back in the day (i.e. 2 years ago). Time to move forward.
This is where the problems start (or end, depending on where you are headed). On one hand it’s hard to scale a Monolith, if you build more and more logic into the same MVC stack you’ll be stuck with, perhaps, a well structured application of horrendous complexity.
On the other hand if you build a thousand microservices in a variety of languages, how do yo manage THAT mess?
There are various container orchestration tools (like Kubernetes, Swarm, Mesos), container deployment services (i.e. GKE and AWS ECS), however few enterprises have nailed the Docker architecture. There are definitely success stories in building out of the infrastructure using Docker or other container technologies (i.e. GKE). Most of these stories come from companies that can afford to spend resources on architects, devops, DBA’s and engineers. Still, as it stands now there are countless debates about how to deploy a well orchestrated and elegant MOA. One size definitely does not fit all in this case and there is a multitude of ways to solve your challenge.
Either way you’re not going to solve this problem alone (DevOps FTW!), and not until you’ve hit a relatively massive scale, will this problem actually need solving. Maybe it’s not the right time to over-engineer.
A happy middle for today (and for those that deal with apps of lesser complexity or traffic requirements) is to offload many typical services to third party providers. Almost everything is available as service now. Background jobs, image processing, authentication, data analytics, logging, email sending, queue systems need not be built within the same MVC stack, rather an Architect should think about what could be offloaded to a SaaS system for a low monthly cost (i.e. search by Algolia) or perhaps a custom-built docker service running in some cloudy space, which handles that annoying image processing.
I guess the point here is that you should not jump into a re-architecture project head first, do not dump everything you have today, and release docker swarms wherever imaginable. There are ways to gradually roll out an improved foundation by decoupling what’s possible, learning about bottlenecks in the system and applying the notion of separation of concerns to these problem areas.
2017 is going to bring us more conversations and production deployments of container-based and MOA. My points and ramblings about Docker, using GoLang or Node, do not mean that PHP is “dying” or anything of that sort … I feel that as developers we need to stay on the cutting edge of things, so if microservices is where it’s at, then why not learn GoLang? It is ideally suited (due to low footprint, speed and parallel processing) for developing tiny containerized apps. Node and GoLang are fun because they allow you to build little services, who are all part of a larger tribe, link them together, and release them as an epic swarm of Docker containers if you so desire.
Yet, all this awesomeness and cutting edge solutions and languages does not mean that PHP is somehow no longer relevant or is otherwise “dead”. We’re definitely going to be building MVC stacks and API endpoints for a while.
One of the issues, which has not been solved by MOA, is that while containers help us to kill the Monolith on the backend we are still faced with many architectural issues in our front-end layer, UI or the view.
We can build an awesomely robust backend application, but in the end it will respond with a JSON, which somehow must be rendered in the client application. Does it matter if the eventual response object arrives from a simple PHP, let’s say, Lumen driven endpoint (URL) or an orchestra of decision making and processing units decoupled by a messaging interface? This, indeed, very much depends on your needs and the requirements of your application.
For this year, learn Laravel keep an eye on Docker, GoLang and definitely focus on the deployment pipeline. Getting from local to production should be smoother than it has been for a while now, especially when building your MVC apps.