March 14th, 2012
I have a friend who is a very experienced PHP and Symfony programmer. He wrote to me:
I’m about to embark on a new project where I will be rebuilding a simple PHP project from scratch (at this new startup I joined as CTO). I haven’t made the decision yet on Rails or PHP/Symfony 2. I’m more comfortable with PHP although I have built a simple Rails app (2 or 3 years ago). I would say I’m an expert level PHP developer and only entry level Ruby developer, but I’m eager to learn. I have not done anything in production yet with Symfony 2. After working with Rails to the extent you have… what would you do in my shoes? Was it a positive experience?
Great question! I’ll try to give you an overview of my experience.
First of all, switching to Rails was much tougher than I thought it would be. There are 2 reasons for this:
1.) Rails is more full stack than PHP
2.) Ruby allows far more meta-programming than PHP does.
About #2: Ruby probably allows more meta-programming features than any language other than Lisp (an infamous blog post on this subject got thousands of comments) . Meta-programming is both good and bad: on the one hand, it means you write less code, because 3rd party code can add itself to your code gracefully, without you having to provide hooks. But on the other hand, if something goes wrong, and you want to debug, meta-programming is a nightmare, for exactly the reason that it can be wonderful: the code is not literal, if some 3rd party alters a core class in a way that conflicts with something you’ve done, good luck finding out what change caused the conflict. With PHP, for the most part, you can read through the code and see what is going on. But Ruby allows “Monkey patching”. You say you’ve done Ruby programming so I assume you know about this. It is wonderful in some ways, but very tough to debug.
The other issue I ran into with Rails is how full stack it is. This is both good and bad. PHP programmers can rely on a stack: Apache, Mysql and Linux. Most of the time we don’t think about this stack — this combo is a great default, and lets you focus on your work. But Rails redoes everything. Nginx is the most common http server, but there is less agreement about what the application server should be. We started off using Unicorn, ran into problems and then switched to Passenger. Passenger is the closest the world of Rails has to mod_php. But with both Unicorn and Passenger, you pass in a lot of the configuration from a config file. In a sense, the command-and-control is the opposite of PHP. In the world of PHP, Apache is in charge of everything, and Apache decides what config options can be adjusted in config files like php.ini. In the world of Rails, it tends to be the other way around: Nginx is the humble servent of Rails, Rails sends config options to Nginx and Nginx adopts itself to what Rails tells it.
For me, the toughest part about getting going on Rails was everything outside of Rails: I had to configure Nginx and Unicorn and setup a Github account, set my ssh keys and write my cap files so Capistrano could handle the deploys. I was lucky that there was a much more experienced Rails programmer on a parallel project and for the most part I could copy over what he had done for the other project — if not that for that I would have been lost.
There are some things I truly love about the world of Rails — it has a package manager called “Bundle” that goes way beyond anything that exists in the world of PHP. This is a real package manager, that checks all dependencies and warns you of conflicts, like apt-get. PHP has nothing like it. And because Ruby allows meta-programming and has a standard format for Gems, it is much easier and safer to incorporate 3rd party code. PHP is somewhat literal, so there needs to be literal hooks in PHP code to allow 3rd party code to work in your system. Symfony has a good plugin system, but still, it is limited by the literal nature of PHP. Since Ruby allows meta-programming, the ease of integrating 3rd is amazing. With Rails, I was surprised at how little actual Ruby code I wrote — for the most part I would just include a gem and write 3 or 4 lines to configure it for my project. There is a gem for everything, and they are of high quality.
I would say that with Symfony 2 the Symfony team is trying hard to imitate the level of decoupled code that Rails has achieved. The idea of “bundles” in Symfony 2 seems like an imitation of “Rails Engines” which is a specific form of a Railtie, which is a Ruby gem. But “bundles” in Symfony 2 still don’t offer the level of separation and decoupling that Rails enjoys.
Also, Rails has a reputation for being heavy. This is true. We struggled with a lot of performance issues. On the one hand, Rails offers far more places where you can tweak configuration till it is working well for you. On the other hand, scaling with PHP seems simpler, partly because you have fewer options: you just throw more Apache/mod_php boxes at the problem.
Conclusions? I would say switching to Rails from PHP is harder than you might expect, but I would also say it is worthwhile in that you end up learning a great deal, and it gives you new insights about the limits of the world of PHP.
Epilogue: having worked a bit with Rails, I find I love its meta-programming but I also feel like it doesn’t go far enough. It is an odd compromise of Lisp with old traditions influenced by C. I am now interested in going all the way to Lisp. I plan to build my next project in Clojure.Source