Drupal 7 vs Symfony 2: overview after 1 year of Symfony development
We’ve decided to switch to Symfony2 development in July 2012, if I’m not mistaken - after 7 years of (mostly) Drupal development.
There were reasons to do that:
1. Not-too-great experience with high load projects, powered by Drupal 7
Okay, Drupal is good enough until you get a project with big expectations in terms of response time for authenticated users. Nginx proxy, boost and memcached help a lot with anonymous page hits, but things are sometimes not good enough when we talk about authenticated user saving some nodes (1 field = 2 inserts to fields and revisions table, 40 fields - and you get super-slow node saving, at least on non-ssd hosting), using ajax stuff like dynamic forms (Drupal form ajax is not bad, it’s just not super-blazing-fast).
Things are getting even worse if you have big website with lots of views and fields, and you just clear the cache on production - your server can become close to non-responsive.
That’s what happened with us in several projects.
Okay, you can avoid using views and write your own replacement for fields which will store data in single table, and own ajax that do not pass all page ids of the page back to the server, - and it will probably be almost as fast as lower level framework code (yii, symfony, whatever) but what’s the point in using Drupal then? The code will be uglier (let’s face it, Drupal API is not as clean and decoupled as Symfony2 API). The amount of time spent on the development will probably be close.
2. Settings in DB
Drupal was built to allow anyone to create complex website without writing a line of code.
It sounds like an unrealistic dream for most of website developers, who are using raw PHP/Ruby/Python/whatever, but not for developers who are using Drupal! Latest version of Drupal and Views is indeed very close to this amazing dream.
As a side effect, when you are creating project where you need lots of programming, you are struggling with settings-in-db approach.
Of course, there are Features which allow to do an impressive deployment stuff.
But then, when you get a bug in features during deployment, which occasionally deletes fields from user profile on production (we indeed encountered this bug in production once - god bless db backups!), you think “I’d better write my own code, it’s too much magic”.
Still, I think that Features are a brilliant piece of functionality and approach.
3. One of our biggest customers fall in love with Symfony2
These guys asked if we’ll be able to create new projects using some robust framework, suggesting Symfony2 after making their own research. It was a matter of big projects, thousands and thousands of man hours. Why not?
4. Drupal8 is using Symfony2 components
That was another sign that Symfony is a good choice.
Just like we’ve chosen jQuery or git for all our projects because of the fact that Drupal decided to go with them, and not with mootools, prototype, and mercurial with bazaar. For business needs, it’s almost always good to use mainstream technologies, though it’s not as geeky and cool as writing a CMS in node.js.
5. Our team (and me, mostly) was eager to learn new system after 7 years of (mostly) Drupal development
Oh yeah. The grass is always greener on the other side of the fence, you know :)
While Drupal is moving forward, some stuff in PHP world was still relatively new for Drupal in 2012. (Annotations, composer, twig, …)
And it’s interesting to use this stuff in real project, not on localhost!
That’s it. Now it’s more than a year passed, and you know what?
After two months of work with Symfony (we were building big and complex ecommerce solution), I realized that it will be a big mistake to switch over completely.
Drupal is still a very good choice for 85% of websites in the world. You don’t need high load and ultra flexibility in 85% (probably, 95%?) of world websites.
And Drupal can be a better choice than Symfony2 for all these projects.
The main (the only?) reason is - rapid and easy development in Drupal.
You can create working Drupal website with the speed of prototyping (if you are good Drupal developer with good experience).
Okay, all the hardcore features still require coding, but you can really deliver working stuff in hours, not days of work.
Symfony is good, but it’s a lot more manual work. The good sign of the fact that this problem is real - is the existence of Symfony RAD edition bundle.
I have a good example - right now when we hiring Symfony2 developer, we ask them to build basic website which contains just registration (basic stuff, FOSuserbundle, we ask to remove username field, just leave email and password) + profile (firstname, lastname) + Facebook login (HWIOAuthBundle).
The average time of implementing this by developers is ~7 hours. And most of the time is spent in writing and testing pretty big yaml configurations for bundles.
The same stuff in Drupal will take ~2-3 hours - drupal install, email_registration module, and https://drupal.org/project/hybridauth or similar for facebook login.
So, it’s harder to do “rocket launch” in Symfony.
Some things that are available in Drupal out-of-the-box (like, permission system) are not easy to do in Symfony2. Typically most of sf2 projects contain pretty ugly checks against current user role. And it’s a bad practice comparing to permissions checking - if you use role checking and you need to add another role which can do the same action, you will have to modify code to add this new role.
Of course, you can implement some kind of security voter or ACL in sf2, and it can be smarter and more flexible than in Drupal, but nobody wants to mess with it without REAL reason. And that’s what I call poor engineering - when “right” choices are too painful so most of developers tend to stick to “wrong” choices.
Symfony components (Doctrine ORM, HttpKernel, Forms, Routing, Doctrine annotation parser, …) leave good impression - they are completely decoupled, and it is really a way to go in terms of architecture, not surprising that Drupal8 uses a lot of Symfony components.
At the same time some third-party bundles leave impression that their creators are in love with over-engineering, not in getting things done.
ORM and db queries
Drupal 7 dev team made a lot of efforts to build own ORM-like code for entities (EntityFieldQuery) but Doctrine2 ORM and query builder are far more robust and polished, and play nicely with Symfony models and annotations, this part is really beautiful in sf2 - that’s a no brainer that Symfony is stronger than Drupal in this part.
Writing your own db queries in code is a pleasure in Symfony, and not a big pleasure in Drupal 7, especially if you are writing ‘raw’ SQL - the main reason is that Drupal 7 fields are a victim of own flexibility (they allow you to change single-value field to multiple-value on the fly, and they are also designed for multilingual websites) - and it requires separate table for each field, while in Symfony2 you have to decide if the field is single-value (than it’s a field in a model table) or multiple-value when designing your db structure. Multiple-value field is typically not a field, but a separate model in sf2.
The Drupal 7 approach is good when you use it from admin interface, but not that good when you dig into code, you need three joins against tables with ugly long names like “field_data_field_send_invoice_paid” just to build a condition to check three fields of a node (unless you use EntityFieldQuery, which designed only for loading nodes - so it’s really a performance hit to use it, that’s why it’s not too popular in our code).
Whole third-party infrastructure of sf2 relies on Github, Composer and Packagist heavily, and it leads to difficulties in tracking which version of the package is good for your installation - for example, some packages can break when you go from Symfony2.1 to Symfony 2.2.
If you still develop in production (ouch!), I bet you will spend a lot of hours trying to understand what to write in composer.json to return your website back to life.
Of course, it happens mostly because Composer and Github were created to make happy everyone in PHP world, not for specific framework.
But for beginner, Drupal module system with 6.x/7.x branches of all modules and themes is way easier to understand.
Another annoying thing is that deployment to production in Symfony2 is significantly more complex than in Drupal.
In Drupal, you commit all third-party modules to single git repo of your project, then you launch git pull, drush updatedb, drush cc on production and you are (typically) good.
In Symfony2, all vendors (third-party modules) are not stored in central git of your project - since most of them have own git repos.
So, when you deploy to production, you need to launch composer install and wait while all packages will update (and your production will be offline during this time).
And if some package git repo is offline - you are in trouble.
Of course, there is a right way to do the deployment - Capifony, based on ruby-powered Capistrano. But you need time and efforts to get used to it.
But when you’re done with complex project in Symfony2, I would say it’s way easier to maintain it over time, and the code is cleaner and easier to understand by another developer. Though, for me, it’s still not a big joy to write lots of these OOP classes when you are developing stuff. You need time to get used to it.
The fresh example of what I don’t like in sf2:
If you want to output standard translated message “The item was created” to flash (flash is session-stored message, the equivalent of drupal_set_message() in Drupal) you need to put:
$this->get('translator')->trans('flash.create.success', array(), 'JordiLlonchCrudGeneratorBundle');
Good luck trying to type it in without editor shortcuts.
and if you compare it to
t('The node was created successfully');
you probably get the idea of the difference between Symfony and Drupal which frustrates Drupal developers :)
Yes, that’s a global function t() - it’s not super architecturally correct comparing to translator service in Symfony, which you can easily override when you need, but.. I don’t care about overriding translator in every project, but I still use standard translator in every project, and I usually use crud generator, and it’s really a lot of typing!
Every time when I write this, I wonder, if this nice guy, JordiLlonch, creator of CrudGenerator bundle, was thinking about all the developers who will have troubles remembering his name, especially ‘iLl’ part? :)
Of course, you can create your own version of global t() (or extend base controller and add YourController::t function) in Symfony2.
1) you will have to do it in every project
2) you will have to explain to your team that there is a non-standard shortcut
3) (in case you do it via global function) you will have this bad feeling that you are going against architecture of your framework :)
Symfony is definitely not about “we have lean and mean code which is fast”.
It’s about “we have good, a bit bulky, but good-for-everyone architecture and 5 levels of caching, and then we have another level that caches cache of cache”.
Let’s just say that single Doctrine ORM has 3 types of cache.
And you can’t completely disable caching of everything, even in dev environment.
The only reliable way to test configuration/annotation changes is to delete cache every time you modify it.
Symfony2 is significantly faster than Drupal. It implements lazy-loading and autoloading everywhere and it’s nice - memory footprint is relatively small. You can update the memory limit - instead of 128mb (drupal) you can (typically) use 64mb (sf2) for the same functionality.
Doctrine is also relatively fast in production. It is clever enough to make single big update/insert for several objects when you call flush(), instead of ugly multiple node_save which can take lots of time to complete in Drupal.
Symfony2 is more “academic”, OOP, professional and serious, faster in terms of performance, easier to maintain for a team of developers.
Drupal is more fun, less code to write, and faster development and deployment, sometimes quirky, quick, and dirty. It quickly moves to OOP in it’s parts, while other parts are still procedural. That’s what I can call ‘dirty’, too.
The same project will cost roughly twice as much developed in Symfony, comparing to Drupal, and will take twice as much time.
I think the learning curve is approximately the same for Drupal7 and Symfony2.
So, we’re still doing Drupal development now.
At the same time, we were lucky to hire pretty talented sf2 developers, so we now do a lot of Symfony2 projects (5 complex projects so far) and even our Drupal team start enjoying it - but these are still two separate teams, one doing Drupal, one doing Symfony2. And I’m pretty sure that knowledge of Symfony2 will help us when we start doing Drupal8 development - that’s what I call synergy :)