Is symfony 1.1 too verbose?

Among the remarks I have about symfony 1.1, the most recurring one is the shift of philosophy between the 1.0 and 1.1 syntax. If symfony 1.0 syntax was made to write code fast, I believe it is not the case anymore with symfony 1.1, which is designed primarily for extensibility.

The result is that a symfony 1.1 application looks a lot more like a Java program. I tend to agree that Object-Orientation is a good thing because it forces you to organize your code in a modular way. But when object-orientation makes you need to keep a symfony book aside at all times and multiply the number of LOC by two, I think it's a dead end.

Disclaimer: I'm not a developer by training. I don't have much experience in web development. I started learning PHP about three years ago, and I don't think that code purity is something you should stick to. I believe in code smell, though, but that's another matter. My main interest is usability in general.

Example #1 - Tasks

Let's see how the new symfony philosophy applies to the new command line utility framework: the symfony tasks. This is a very powerful addition to symfony 1.1, made to allow an easy parsing of CLI arguments and options, and to write CLI scripts in an extensible way.

Here is a typical task initialization method, taken from sfLogRotateTask (for details about the syntax, please refer to the symfony 1.1 documentation):

protected function configure()
{
  $this->addArguments(array(
    new sfCommandArgument('application', sfCommandArgument::REQUIRED, 'The application name'),
    new sfCommandArgument('env', sfCommandArgument::REQUIRED, 'The environment name'),
  ));

  $this->addOptions(array(
    new sfCommandOption('history', null, sfCommandOption::PARAMETER_REQUIRED, 'The maximum number of old log files to keep', 10),
    new sfCommandOption('period', null, sfCommandOption::PARAMETER_REQUIRED, 'The period in days', 7),
  ));
 
  ...
}


To be able to write a task by yourself, you need to know what an sfCommandArgument is, what an sfCommandOption is, and you need to know their constants as well. That means that the number of things to learn is quite important. And why do we need to instantiate a new object to set arguments, since the only thing that addArguments() accepts is an array of sfCommandArgument objects? Because, sometime, you will take advantage of the fact that you can pass a subclass of sfCommandArgument to extend the task framework.

Developed according to the symfony 1.0 style, this would probably give:

protected function configure()
{
  $this->addArgument('application', true, 'The application name');
  $this->addArgument('env', true, 'The environment name');

  $this->addOption('history', null, true, 'The maximum number of old log files to keep', 10);
  $this->addOption('period', null, true, 'The period in days', 7);
 
  ...
}


Do you see the difference? The latter is maybe not as easy to extend, but for 90% of the cases, faster to write. Besides, the addArgument() method does not prevent you from using the long version with addArguments(), so you get both extensibility and brevity.

Note: By reading the above code, you don't know what the null and true parameters stand for. It is a matter of taste, and longer to write, but I'd rather have my method calls look like the following when the method takes many arguments. That way, every method call in your application is a useful reminder of the API.

protected function configure()
{
  $this->addArgument('application', $required = true, $help = 'The application name');
  $this->addArgument('env', $required = true, $help = 'The environment name');

  $this->addOption('history', $shortcut = null, $required = true, $help = 'The maximum number of old log files to keep', $default = 10);
  $this->addOption('period', $shortcut = null, $required = true, $help = 'The period in days', $default = 7);
 
  ...
}


Fabien added an addArgument() method to sfTask not so long ago, but it just seemed useless to him to duplicate the method signature. I think he did that just to make me stop yelling. You, developer, should learn The Right Way of Doing Things, and the right way is the longer way. If you can't understand or learn the longer way, bummer, you can't use symfony.

Example #2 - Events

The event system is another great addition to symfony 1.1. It extends the principle of mixin to allow more runtime class modifications. Once again, the symfony book is up to date on this part, so you should read the related chapter if you need to understand the syntax.

So here is how to allow a class to be extensible by way of a generic __call() in symfony 1.1:

public function __call($method, $arguments)
{
  $event = $this->dispatcher->notifyUntil(new sfEvent($this, 'foo.method_not_found', array(
    'method'    => $method,
    'arguments' => $arguments
  )));
  if (!$event->isProcessed())
  {
    throw new sfException(sprintf('Call to undefined method %s::%s.', get_class($this), $method));
  }
 
  return $event->getReturnValue();
}


And here is how you register a new bar() method with this system:

$dispatcher = sfContext::getInstance()->getEventDispatcher();
$dispatcher->connect('foo.method_not_found', array('myClass', 'listenToFooMethodNotFound'));

class myClass
{
  public function listenToFooMethodNotFound(sfEvent $event)
  {
    $parameters = $event->getParameters();
    switch($method = $parameters['method'])
    {
      case 'bar':
        $this->bar($event, $parameters['arguments'])
        return true;
      default:
        return false;
    }
  }
 
  protected static function bar($event, $arguments = array())
  {
    // ...
   
    $event->setReturnValue($result);
  }
}


As I wrote the documentation for this feature, I couldn't refrain from thinking this could be a lot easier. With symfony 1.0 philosophy, I guess you would only need to write:

public function __call($method, $arguments)
{
  return $this->dispatcher->handle($this, 'my.class.event.name', $method, $arguments);
}


And you would probably register a new method this way:

$dispatcher = sfContext::getInstance()->getEventDispatcher();
$dispatcher->addMethod('foo.method_not_found', array('myClass', 'bar'));

class myClass
{
  public function bar($object, $arguments = array())
  {
    // ...
   
    return $result;
  }
}


You can guess how the handle() and addMethod() methods of sfEventDispatcher could do all the dirty job for you. That would save you a copy/paste from the first version of the code, would be less error prone, and after all, if the program has less lines, then it's cheaper to maintain.

But, according to Fabien, that would be hardcoding the way you throw an exception in __call(), and this addition would only be useful in a very minority of cases. While the fact that you pass to notify() an sfEvent instance instead of a simple list of parameters is, once again, based on the idea that you will sometime find it convenient to subclass sfEvent. Which I think will never happen before symfony 1.2 at least.

Example #3 - Forms

Don't get me started on forms. I already wrote a post about sfForms to say that it missed an important part, and that code usability had been left aside. I still think so. Fabien doesn't.

Oh, by the way, do you know that the First Project Tutorial in symfony 1.1 showcases the new Form framework? If that doesn't discourage newcomers, I think nothing will. I wish good luck to the one who will try to make this tutorial newbie-friendly.

Conclusion

Symfony 1.1 adds a ton of wonderful features to symfony 1.0. From a technical point of view, this is a more complete, more coherent, more beautiful piece of code than symfony 1.0 was. It kicks ass and I believe that it's more powerful than any other PHP framework out there.

On the other hand, I think that symfony 1.1 is more verbose, and therefore more error-prone, than symfony 1.0. It forces you to constantly look at the book for syntax description. The book cannot describe everything - it is just a guide on how to use the framework. It should remain as small as possible to keep readable. The book cannot go into the details of sfCommandArgument::REQUIRED or sfWidgetFormSchema. That means the book will not be enough to use symfony 1.1: You will need to know the full API doc as well, even for the basic uses. Fabien knows the API by heart, so he doesn't need any documentation. But you, my friend, you will sweat a lot to learn all the changes.

The heart of the problem is that, to use symfony 1.1, you don't just need to learn the usage guidelines, you also need to understand how it works inside.

I disagree with the philosophy shift symfony is taking. I think it should stick with the "KISS" motto, and it could do so without sacrificing extensibility. If the price to pay is a little more code in the symfony base, then symfony should pay this price - not the symfony users.

I'm tired of writing a book that looks more and more like an API documentation. I don't feel like explaining the core symfony classes to developers who just wants to use the framework to build an application. I think that The Definitve Guide To Symfony doesn't really make any sense anymore. You want to know how to use the framework? Well, read the API doc and guess. After all, that's what all the other open-source projects do.

Maybe I'm the only one thinking that. But, as I said at the beginning, I'm no developer.

25 Comments so far

  1. naholyr on May 5th, 2008

    I couldn’t agree more with you…

    I must admin this is the main point which prevents me from bringing 1.1 into my company. It was already kinda hard to teach Symfony to my collegues, and it was even harder to get rid of their comments, especially “pfff, how heavy it is, I could do this in a minute with my own hand-made-and-not-maintained library” but I could do it because the tool brings many advantages for very few counter-parts.

    I know I won’t be able to make 1.1 accepted, because now the counter-parts get really greater, the framework gets harder to learn, and a lot of interesting shortcuts are lost.

    For example all the gain done with “convention more than configuration” is lost when you want to create a quick task for a project. And I won’t be able to argue with them when they will say that. And because of this I know Symfony 1.1 will not be introduced in my company, until I have made a lot of work to create the required shortcuts.

    One last thing, to answer some comments you got :

    “that would be hardcoding the way you throw an exception in __call()”
    So what ? Aren’t a lot of exception messages already hardcoded ?
    Anyway, this could be handled as an optional parameter.

    “and this addition would only be useful in a very minority of cases”
    In fact, I think it would be useful for 90% of the event-management cases.

    I loved this philosophy of Symfony : all the usual work is already done, suiting 90% of your needs. And the remaining 10%, well you have all the freedom needed to suit it. I would have expected Symfony 1.1 to ease the work done on those 10%. Anyway, I’ll now expect 1.2 to do that ;)

  2. stephen riesenberg on May 6th, 2008

    I’d buy you a beer, but I don’t know what you drink… And you’re in France, which is a long flight. Thanks for the update.

  3. Pastor on May 6th, 2008

    Example #1 - Tasks

    Since most developers are using IDE for programming, the first way is much easier to write(code completion will do the job for you). Fnd it’s much easier to understand the meaning of sfCommandArgument::REQUIRED , rather than just boolean variable in the arguments list.

    The code should tell you what he do.

  4. Loïc on May 6th, 2008

    Thanks for this post, it clears my mind about Symfony 1.1 as I was wondering how much time I would need to cleanly port my core projects from 1.0 to 1.1 and what benefits This would produce, too heavy at the moment…
    Loïc

  5. Skyblaze on May 6th, 2008

    are you saying we have to switch to zend framework? :)

  6. gzorg on May 6th, 2008

    As a developper, I understand clearly the interest of having verbose code with clear use of objects and class constants.

    As a symfony developper, using eclipse, code completion explains helpers syntax for example, so writing code like add(something, null, true) is not very hard, and is clearly easier to read and maintain.

    Each time we need an help while coding, we refer to the symfony book which is finally the only exhaustive reference and quicker way to solve a question, with quick reference cards of course.

    So we hope the new Symfony book will can explain as simply as today the concepts with tips and tricks and all that we love in the first one.

    Good luck François!

  7. cedric on May 6th, 2008

    Couldn’t agree more. I’ve been developing with the 1.1 for 2 months now, and as I was tired to google for thing no one had written before (as you say, no one enjoys writing an API doc), I started to dive in this API… and honestly? it’s a boring way to work, and I don’t have much fun.

    Like Naholyr, even if I have this patience, I really doubt my employees will, which is a shame because this evolution is really powerful.

    At the end, we all are very thankful for your documentation job, and your simple and practical tone, which has, I am sure, driven many new devs to this framework.

    One of the key aspect I had been told when I was in Yahoo! and was introduced to Symfony back in 2006 was its simplicity, and the fact that it was funny whilst professional. It really should not lose the fun part.

  8. Raise on May 6th, 2008

    As with others commenting above, I also use an IDE which is very helpful in giving me fast, inline access to the API for parts of symfony that I don’t know by heart.

    That said, I agree completely with you that this new sfForm approach is a step in the wrong direction for symfony.

    All the designers here have warmed to the symfony helpers that populate the template files they need to edit, even understanding the difference between slots, partials and components. This is due to some informal training by me but also the excellent cheat-sheets produced by Andreia Bohner:

    Having to retrain them to edit pure PHP code to adjust forms is something I will find a very difficult sell, not only to the designers themselves but to management who also love symfony only for its speed, not its elegance.

    Sadly, I also agree the Definitive Guide is mostly redundant if we are expected to rely so heavily on the API for the answers.

    I will be making use of the sfCompat10Plugin for quite a while, it seems.

  9. Romain Dorgueil (hartym) on May 6th, 2008

    Hi François.

    Something you maybe forget to say about tasks is that with the new system, we don’t have to use old iterative batches with random syntax and approximate environment.

    Your CLI tasks are now unified, perfectly integrated to symfony CLI and you have good control over the environment you’re using.

    This may seem verbose, extensive, whatever… But that’s a huge uniformisation of batch tasks on which I’m gonna write a blog post about soon.

    Yes you need to explicitly declare arguments, options, required, optional stuff… But from a user point of view (I mean the client, the project manager or whoever will directly use the app on production/development servers) it’s a huge step forward:

    • Tasks are self documenting
    • Tasks are uniforms syntaxically
    • Developper can provide default options, and somehow advanced ones for testing/dev env…

    Short syntaxs are often looked at as sexy ones, because one thinks it’ll make one goes faster…

    In fact that’s pretty true when you begin using this kind of tools, but very soon, troubles will show up in debugging, maintenance, and capabilities-extention sessions. Then you realise that you don’t know what is really going on behind the scene.

    I’m pretty sure not many people gone through the process of knowing what the magical sfContext::getInstance()->getController()->dispatch(); was doing in symfony 1.0 front controllers, and I bet not much knows why the little 4 header lines bootstraping a symfony 1.0 batch script gets autoloading and database manager up, running and useable…

    So symfony 1.1 is more verbose?

    Today’s great (PHP) IDEs (like eclipse, textmate or my ion3/xfe/gvim association) can do pretty much code completion, code templating and identifiers declaration jumps.

    So symfony 1.1 is more verbose? Well if that mean users will get to understand what they’re doing, it’s a great forward jump imho.

  10. François Zaninotto on May 6th, 2008

    Romain,

    Don’t get me wrong: I never asked for anything to be removed from symfony 1.1. If you look carefully at all the examples I give in this post, I always suggest to add new, simpler methods, on top of existing ones, to make the API more accessible.

    Think about jQuery: they offer a powerful bind() method, capable of binding a function to all kinds of events. But they also offer a simpler click() method, to bind a function on an onclick handler. I think symfony 1.1 deserves the same ‘polishing touch’, that I would rather call a ’simplicity layer’.

    With all the benefits of simplicity without any sacrifice on extensibility, symfony 1.1 would be almost perfect. Documenting the basic API in the book would be much easier, as it would be easier for a beginner to dive in. Then, if a developer wants to look at the API doc, follow an “advanced” training or buy a “Secrets of symfony” book, I don’t see any harm.

    The more people use symfony, the more business opportunities arise. I think it’s in the interest of everybody to design symfony 1.1 as a simpler tool, rather than to restrict its use only to the best developers around.

  11. Skyblaze on May 6th, 2008

    you scared me…..now i’m in doubt if i have to pick symfony 1.1 or zend framework 1.5 -_-

  12. Alex Farran on May 6th, 2008

    Compared to using mixins, the event handler code looks way too complex. For the common cases the code should be as simple as possible. Even the 1.0 mixin code looks a bit long winded compared to languages that handle mixins natively.

    An IDE will only help so much. It helps you write code quickly, but you still have to read it. Concise code that expresses what it does, rather than how it does it is easier to scan.

    A higher level API covering the common cases is a very good idea. And it’s not just of benefit to beginners. Advanced symfony developers should only have to work with low level code when they need to.

  13. Piers on May 6th, 2008

    Oh good, some juicy discussion…

    :)

    ” I’m tired of writing a book that looks more and more like an API documentation. “

    The 1.0 book nailed it -a fantastic balance of solid overview without leaning too far into serious API clunk.

    Taking a wander the through the 1.1 documentation, it still seems nice and clean.

    ” I always suggest to add new, simpler methods, on top of existing ones, to make the API more accessible. “

    Sounds like a great idea. I too use advanced IDE features, but I really like the idea of a set of proxy methods for ridiculously simple usage.

    I think there should be a set of proxy calls to simple usage patterns… but if you’re going to go and move into things like filter chains and event triggers, you are probably the sort of developer who will be relying on a very different set of tools to get the job done.

    By tools I mean, experience in the required concepts, knowledge how to trawl API docs and API code… you might also go hunting for advanced usage examples in tutorials and other peoples code etc…

    “you scared me…..now i’m in doubt if i have to pick symfony 1.1 or zend framework 1.5 -_-”

    1.1 really does have great features. Well worth the effort. The Symfony core group have really made some huge leaps and bounds with what’s going on under the hood. Awesome!

    Every time I sit down and write some docs on a piece of code I’ve written, I tend to go back and simplify the source. Documentation is such a good way to test overall concepts. It also seems to highlight the separation between engineering code and communicating code. I think it’s a very good thing for Symfony that this sort of discussion and difference in opinions exists. Too many projects get polarised by either “radically complex” or “radically simple” ideals.

  14. NiKo on May 7th, 2008

    We have the chance to have an open framework, with an open architecture which enables to extend the functionalities easily through plugins.

    To me, extreme simplification and “magic” stuff should sit at max in such extensions, not in the core. The core must be explicit over implicit, serious and reliable.

    Also, I think the documentation effort is very important here, because the framework has evolved a lot and people could be lost or afraid very easily seeing the API changes.

    That’s where you got something to do François, symfony needs you ;)

  15. Tony on May 7th, 2008

    I’m sorry to read this post, François.

    For me, a key factor in my decision to use Symfony (as opposed to other PHP RoR-like frameworks) was the fact that I could buy a well-written book to teach me, and serve as a reference.

    If your heart isn’t in it, I suppose the book will die and I, and other Symfony users, will start to look at different frameworks.

    I hope that this situation can be resolved and that symfony will continue to grow to serve the needs of all levels of developer, not just the Eclipse Ninjas.

  16. zero0x on May 7th, 2008

    this is why I like Rails :)

    but I use symfony ;)

  17. Diego on May 7th, 2008

    Great post! And I think the same as you.

    I hope that in future versions symfony includes “simpler” API and functionality. Personally I’ll stick with symfony 1.0.

    Please Fracois, keep us up to date with the news related to this. Thank you very much!

  18. Brett on May 7th, 2008

    At the heart of all successful open source projects is strong documentation. For Symfony this is no different. It is necessary for the average developer to understand how to effectively use the framework, which is what the Definitive Guide is for. It is a guidebook not a bible.

    Francois concentrate on writing a good guidebook and let the API documentation take care of itself. You can point to the API when you need to. What you are doing it insanely helpful. I appreciate your work as I am sure all other Symfonians do.

    Speaking of the API documentation, I wish it were more like the PHP Manual. Mainly, I wish people could comment on methods and members to clarify the details of how they actually work. That would be helpful.

  19. Joshua May on May 9th, 2008

    Well, I have to say that I disagree with the post.

    I can’t recall a point in time when symfony ever had a low barrier to entry. As a reasonably educated developer (a software engineer!), and well skilled, I still had my own issues learning symfony 1.0 (well, 0.4 at the time). And I know for sure from #symfony that it hasn’t been easy for a lot of people.

    I don’t think symfony needs to cater for the lowest common denominator, and to a point, I prefer that it doesn’t (in my own selfish I-don’t-want-to-maintain-your-crap kind of way).

    I’m really a fan of the new forms. Admittedly I’ve found some hiccups, but I mean how nice is it to have inheritance in forms? I’m making a lot of use of that. Less copy/paste, and less confusion IMO.

    I don’t support the notion that designers should have easy access to the templates. I don’t want a designer messing with my code in the first place, really. And I understand some people are different, but my theory is that you have a web developer to do that - preferably someone with some kind of programming knowledge that can write functional tests as they implement the UIs.

    At the end of the day, it’s not going to be a silver bullet, and not everyone’s going to be happy with every decision.. Hm.

  20. halfer on May 9th, 2008

    Hi Francois,

    I don’t know anything about 1.1 - it’s on my to-do list to look at! - but I do fully agree with the suggestion that one shouldn’t have to know the code internals to use a framework productively. As you know I am a long-time symfony fan, but I’ve only touched on a small bit of core code - on the whole I’ve not needed to.

    I think the potential philosophy you outline for symfony 1.1 sounds perfectly reasonable. I think if your position gains popularity (and this is no criticism of Fabien, whose work I strongly admire) there may be a change of mind to include the “polishing methods” in the core that you are suggesting.

  21. digitalbase on May 13th, 2008

    Very interesting read,

    i’ve had the chance to play around with the symfony 1.1 form system, and i like it alot.

    You could use the argument that it is getting more complex, but i really do think that the new form system was a good decision.

  22. Keith on May 13th, 2008

    This is absolutely true. I have argued from the very beginning that just because the framework handles things according to commonly held MVC conventions doesn’t mean that the user should suffer.

    A great example is forms. By removing what is essentially view specific code from the view and putting it in the controller the differentiation between the view and the controller from a user’s point of view is diminished. That is unacceptable.

    I have done 3 full Symfony projects that are now in production and I don’t think I’ll ever unfreeze them because of what it would mean to upgrade them to 1.1.

    Not to sound like chicken little, but I refuse to have my developers and contractors using 1.1 and I feel like most savvy development shops will shy away as well given the massive philosophy shift between 1 and 1.1.

  23. Ian on May 13th, 2008

    Well I have finally had a chance to really dig in and get to know the new form system in sf. It definitely has major pros and major cons.

    I agree that the concept is hard to grasp and it can be very complicated/confusing to properly build your first non-standard form. This is especially true if you don’t use propel and need to figure out how to inject object data into your form class. If you can’t figure this part out (which I doubt a lot of newcomers will without detailed documentation), the whole form system is going to seem like a monumental amount of work to use.

    I can easily see how, from a designer’s perspective, the system is extremely over-complex. In the past, our firm has always designed mock-ups first using the 1.0 form helpers, and the developers have followed-up with “live code” once the action is complete. Now, with the new system, the designer has to either wait for the form class to be completed, or use standard HTML to build the mock ups (which is a bit slower).

    Overall, once you get past the steep learning curve, I found it to be an improvement to how forms were handled in the past due to the tighter integration of validation and error handling, and we’ll be using it for new projects in the future.

  24. blacksun on May 15th, 2008

    I think your point is crucial, François.
    While it’s easily seen that the proposed API is technically “the right one”, the “simplicity layer” you propose would give a big usability advantage to symfony 1.1.
    To work with symfony 1.0 is a great developer experience. You can go fast while producing a clear code that is also robust and maintenaible.
    You can concentrate exactly on the logic of the thing you’re working on… Come on, I think we all know the feeling. ;-) IMHO this is due to the concurrence of various causes :
    - power and robustness of the framework: no easy complains about how things are done behind the scene, you can trust it
    - completeness of the framework: symfony never let you alone whatever task you’re accomplishing
    - an easy API for all common tasks: you can’t stay concentrate if you have to consult docs every 5 minutes
    - extensive documentation for all cases

    It will be a mistake to drop one of these elements, they all are necessary.

    I think Alex Farran is right: we all deserve an easy API, not just beginners!
    Let’s keep the complexity of our code at the same level of the problem we’re handling: if we don’t need the full functionality of a feature, we should avoid to be reminded of it in every method call.

    @NiKo, the plugin idea could work but I think it’s just ugly from an architectural and philosophical point of view. The code you’d need to put there is not specific to some features. And how will you explain this in the documentation? A chapter about the plugin? “If you have the sfSimpleApiPlugin installed you can also do this like that”? (Imagine the François’ form yaml example after 20 pages about sfForm)

  25. Éric on May 15th, 2008

    Hello François, I haven’t even tested sf1.1 yet, so I won’t argue about its verbosity.
    But if you say so, I’m a bit frightened about the next symfony release : by my (pretty little) experience, the more you ask developers to use an API which is not friendly-user designed, the harder it is next to refactor and to add features, keeping a good backward compatibilty.

Leave a reply