You might think there was a big meeting where we decided that our primary framework would be Symfony because blah blah blah. I’m afraid to disappoint you but the true story is more trivial.
Initially we had to use Symfony2 instead of Yii as it was one of the critical technical requirements for a project we were going to undertake. So we had a quick look at Symfony2 documentation, cookbooks, new features, etc. At that point everything looked very familiar – the same MVC concept, only a different template engine, ORM etc.
Yes, Symfony2 had a dependency injection container but it didn’t change things much. Moreover, we had a few team members with awesome experience in developing projects with Symfony v1.
We knew that migration would not be easy and we would have to invest more time in maintaining our normal development speed. But we were open to a new challenge and experience.
This project had crazy deadlines. In addition, we were using Symfony the same way as Yii. We tried to keep to the principles, styles, approaches which we had seen working great for Yii. And that was not really a good idea, but it was fine for the first time.
The next project involved using Symfony as well.
We tried to eliminate all misunderstandings and precisely followed Symfony philosophy.
Basically we started doing things Symfony way and that resolved many architecture issues. It was the first time we got acquainted with Composer/Packagist, PSR-2 and many other nice tools. Finally, we got closer to the Symfony community.
I guess we achieved true success and satisfaction with the new framework only working on 3d project. Since then we haven’t considered going back to Yii.
Now I will try to explain in more detail why we’ve decided to stay with Symfony, what we especially like about it, and what useful features it has.
Jumping a bit ahead, I’d like to share results of our internal team voting. We’ve decided to ask all our team members if we are on the right track and if they want to switch back to Yii.
I have been personally surprised to see nobody voting for Yii. Originally some team members used to be skeptic about Symfony, criticize it for being a pure enterprise, and favor Yii for being simpler to work with. But finally, they’ve let the Symfony concept penetrate their minds and there is no way back now :) Some have tried to revert to Yii in a few micro projects, but finally showed the white flag.
So why have we switched to Symfony2?
Actually it’s all about code management and maintenance.
From the very beginning, coding fast is really easy. We’ve never had problems with this and I’m sure you neither. Issues will show up later, when a project has grown up and become long-term. Almost all our projects are long-term (from 2-3 months to a year or even more).
That’s why it is critical for us to use approaches and techniques allowing us to effectively manage our code in the long run.
When we were working on year-long projects using Yii, it was hard to keep them flawless after 3 months of development. We always faced small but annoying issues, had to apply little workarounds, hooks and so on. Yeah, it worked but was no fun to do.
We want to keep our code base well-organized and follow some clear principles to protect code from corruption. That is our main concern. No matter how long a project is going on, one month or one year, we want to always feel happy about our code and pursue interest in development. There shouldn’t be any hooks and workarounds. Honestly, hooks are killing project teams. Who likes dirty laundry? It usually happens like this:
OK, today I will quickly do this small workaround and tomorrow I will find and replace it with a better solution.
Remember, it is a wrong path.
What code management issues have we faced with Yii?
TDD (test driven development)
First issue is code testing. Tests should be written easily. Nobody will follow TDD if one simple test requires mocking a half of application services. It is an overhead. And Yii wasn’t actually helpful enough.
Global service locator Yii::app() just kills attempts to write tests. You start with one test, then you understand you need to mock this service and another one, and both of them depend on another service… bah! Many services in Yii interact with each other. That sucks.
Another problem is tight coupling. It is also tricky to perform application decoupling. Ideally, we should not do this as it should be initially decoupled.
So it is really hard to follow TDD with Yii. Yes, they have CWebTestCase, fixtures, base integration with PHPUnit and so on. But it would be much more useful to test services/models without mocking other services and framework classes.
Implementing the ActiveRecord pattern is fine. It’s really useful for beginners. But Yii active record is too simplified and again, too tightly coupled. Obviously, an entity should have connection in order to save data without directly passing it. But there is no reason to apply this to the whole class.
Yii active record doesn’t suit our needs also because of missing separation between entities and entity manager (queries).
In Yii we have to use static methods for querying models and non-static methods for model logic. Yii has a single instance for ActiveRecord and ActiveFinder, and it’s not cool when queries get mixed with entity getter/setter.
Another point regards static methods for querying. We’re talking about just a static state of class. And if you want to mix a few conditions you have to merge criteria. With Propel I do the following:
and keep my filters/criteria separately. In Yii you define them with arrays (you can’t create conditions dynamically) and then merge arrays or criteria which is quite boring. You also can’t have a few query classes extended from base one, where you separate filters/conditions based on domain business logic.
We need something more practical.
I know it has some issues too and generates code far from the best coding standards. But it works for us and we get clear separation between entities and queries.
The main things we like about Propel: real getter/setter (we can have a look at how they are implemented and override them if needed), db schemas and migrations generation, behaviors that actually generate add-ons, a rich set of generator properties, and integration with some Symfony components like forms and validators.
I know Yii team follows its own coding style and that’s fine. But internally we have a different one and that has become an issue.
Actually, we haven’t had documented code guidelines before. We’ve made a few attempts to write them down but it is too boring to write about intentions, class names, brackets and so on. It also requires much time. We’ve secretly had some common standards but it hasn’t just been documented.
The problem is that our code guidelines are quite different from those the Yii team uses. We have contributed some extensions to the Yii community and, of course, we have tried to keep our extensions similar to native Yii code. In the end, we had to switch between different code guidelines all the time. For extensions we used Yii code guidelines, for real projects our own code style. Not cool.
We want to use something global. In our code, in the components we use, and in the frameworks itself.
Now we follow PSR-2. We have been close to it and migration has gone super easy. Symfony2 follows PSR-2. Many components follow it too. It works for us and we really appreciate php-fig for their work. I know there are many polemics about PSR, but most of them are related to PSR-3. PSR-2 is good enough, at least for us.
One more thing is namespaces. As you know, Yii does not use namespaces, and it is not helping when you’re building applications. Namespaces help to shortcut class names, help with classes autoloading and lots more. In general, we feel more comfortable with namespaces rather than without them.
Let’s see how we used to get an extension in Yii. First we needed to find it on the Yii site, download, manually copy it to the project directory, attach it to the config. Then we had to monitor the site for updates. It was fine then, but is not now in 2013.
Right now we use composer. It’s really awesome when you can just define project dependency and run updates. The tool will download extension/lib/component/bundle or whatever you want, setup autoloading. Composer will also take care of all component dependencies and download them. With one command you can update all components to the most recent version. You can specify which version to use. If you want to download test and dev versions, that’s easy too.
There are some other great things like contributing, for instance. It’s super easy to publish your package and make it globally available. It’s easier to define versions, fork extensions, send pull requests and so on.
Composer is an extremely useful tool. That’s exactly what the PHP community needs.
We use Composer to manage our dependencies. We don’t keep external dependencies in our repos at all. What we need now is just to keep composer.json in the current state.
Let’s get back to code maintenance. Most often when people want to say that the code should be cleaner, they say they need the right architecture. What does that mean?
First of all, it means that software development should be based on some principles and follow good practices. So yeah, we want our software be principled. That’s why we try following SOLID and not following STUPID. Symfony helps us with this. Symfony2 architecture relies on the same principles and that’s super awesome.
I want you to get me right. We still have warm feelings for Yii, keep sending best regards to the Yii team, since they have done and are still doing a great job. It’s an awesome framework, and we have spent several man-years writing code with this framework, contributed a number of extensions and advised it to many beginners across different forums. It just doesn’t meet our needs any more. We still follow updates regarding Yii2, and have been waiting for it for so long… But we need to move on. And the next destination of our trip is Symfony2.