XHTML.net

Technology talks by Loïc d’Anterroches

News, articles, PHP, scripts, XHTML/CSS, …

  1. Home
  2. PHP: Hypertext Preprocessor
  3. Pluf - Framework en PHP5

Quel framework PHP/Python/Ruby choisir si vous devez apprendre un nouveau aujourd'hui ?

The 2010-04-27 at 09:20 by Loïc d'Anterroches filed under Pluf - Framework en PHP5.

Supposez que vous codez avec Symfony et que vous le trouvez lourd et n’avez pas la patience d’attendre la version 2 qui devrait améliorer cela ou que vous codez avec Pluf et que si vous le trouvez super rapide vous voulez découvrir autre chose et vous êtes séduit par les sirènes de Django ou Ruby on Rails. En gros, vous voulez changer et vous ne savez pas très bien quel framework choisir pour votre changement. Si vous avez la chance de pouvoir prendre le temps d’apprendre comme vous voulez, voici mon avis, issu de 15 ans de développement de sites internet :

  • Symfony : Poubelle.
  • Pluf : Poubelle.
  • RoR : Poubelle.
  • Django : Poubelle.
  • Votre framework inspiré de Django/RoR/etc… : Poubelle.

Une autre question ? Poubelle.

Si vous devez apprendre quelque chose aujourd’hui pour demain, n’investissez pas votre temps dans des frameworks conçus sur des concepts vieux de 10 ans. Investissez votre temps dans des concepts nettement plus prometteurs.

Les problèmes des frameworks actuels

Le premier problème est l’ORM. Vous allez traîner avec plus ou moins de succès une correspondance entre votre base de données SQL et votre code orienté objet. Par exemple pour la homepage de The Onion, codé avec Django, ils ont besoin de 800 ms pour générer le SQL et 400 ms pour faire les requêtes et cela ne prend même pas en compte le coût pour convertir le résultat de la requête en objets Python.

Que vous utilisiez un framework ou un autre, vous aurez ce problème dans la majorité des cas.

Le second problème vient du langage et de la manière d’écrire votre code car il est toujours implicitement séquentiel : Faire A, puis B, sinon C, puis D, etc… Je prenais l’exemple suivant avec l’excellent piouPiouM (Si vous cherchez un excellent développeur web sur la région lyonnaise, il est bientôt dispo) :

Avec Indefero vous listez le contenu d’un répertoire de votre dépôt Subversion, le répertoire contient 5 fichiers à 5 révisions différentes. Combien vous faut-il d’appels systèmes à Subversion pour les lister avec le message de commit de chaque révision ? 6 appels. 1 pour la liste, 5 pour les 5 révisions. Supposez qu’il faille 15 ms par appel pour récupérer l’information, cela donne un temps de 80 ms pour récupérer l’information. Pourtant, vous pouvez faire cela en 40 ms.

Vous récupérez la liste, puis vous lancez en parallèle les 5 appels pour récupérer les messages de commit. Comme faites vous cela en PHP/Ruby/Python ? Vous ne le faites pas, car les bibliothèques sont codées pour bloquer sur les appels systèmes et le langage lui-même est conçu pour ne pas vous permettre de faire cela. (Ok, vous avez Twisted, mais ce n’est presque plus du Python…).

Votre langage et votre framework sont lourds via l’ORM et par définition non performants de part leur structure.

Le premier sauveur, node.js

node.js est un projet qui repart d’une feuille blanche et est conçu pour ne jamais bloquer. Vous programmez avec des callbacks et toutes vos actions peuvent être lancées simultanément. Surtout, toutes les bibliothèques sont conçues pour ne pas bloquer. Vous pouvez donc exécuter en parallèle des séries d’actions pour récupérer les informations qui vont être utilisées pour construire votre page. Vous laissez le soin à votre OS de gérer la pile des accès disques pour avoir une exécution dans le meilleur sens…

Le second sauveur, JSON

Si vous n’avez pas besoin des fonctionnalités ACID de votre RDBMS, utilisez autre chose (même un simple stockage dans des fichiers textes) mais stockez au format JSON. Vous pourrez stocker aussi cela dans MongoDB. JSON, c’est simplement des listes, dictionnaires, en gros, un stockage simple des structures de données que vous avez normalement dans votre programme, pas de lourdeur dans la conversion entre votre stockage et votre code.

Au final, node.js, JSON et MongoDB

Si je devais démarrer un projet avec un peu de temps devant moi je prendrais :

  • Node.js pour le faire tourner.
  • MongoDB pour stocker les données.
  • JsonTemplate pour formatter les données.
  • Un système à la Pluf pour router les requêtes.

Cela donne un système haute performance, non bloquant, sans la lourdeur d’un ORM et nettement plus "future proof" que le gros des troupes du moment.

Bien entendu, je continuerais d’utiliser Indefero pour héberger mon code (non, ceci n’est pas une publicité).

Comments from readers

desfrenes said:

cf le micro-bench que j'avais fait de node.js: http://www.desfrenes.com/blog/post/node-js-plus-de-clients-moins-de-serveurs

La techno est très intéressante, même si je pense qu'il va falloir résister à la tentation de la mettre à toutes les sauces, même quand ça n'est pas judicieux.

Eric said:

Tout d'abord éviter de faire 1x5 est souvent possible, à base de jointures et/ou de code bien organisé.

Il y a aussi l'ORM DataMapper sur Ruby qui se rend compte de pas mal de ces situations et qui sait que quand tu vas demander un jeu de résultat puis que tu vas chercher une liaison séquentiellement sur chacun de ces résultats, il peut lancer une requête directement sur les 5 puis trier dedans.

Enfin, sur du ruby toujours mais je suppose que c'est similaire en python, tu dois toujours pouvoir lancer un thread pour ta requête et attendre le résultat.

Reste que la plupart des gens développent en séquentiel et que tu as beau utiliser un framework ou un langage à base de templates, si tu conçois les choses séquentiellement, tu ne gagneras pas de temps.

Sinon partir de "on peut avoir de meilleures performances avec une conception à base d'événements et des systèmes parallèles" et en tirer "frameworks actuels = poubelle", il y a quand même tout un monde.

Loïc said:

Eric, pour les frameworks actuels, je dis "poubelle" dans le contexte qui est "apprendre quelque chose de nouveau" et uniquement dans ce contexte. C'est d'ailleurs le titre de ce billet.

L'ORM DataMapper c'est un pansement sur une jambe de bois. Ce sont des implémentations (on en trouve aussi en Python/PHP) très ingénieuses et bien pensées qui ne font que compenser le décalage entre la manière de stocker l'information dans la base et son utilisation dans l'application. De même lancer un thread, c'est bon pour quelque chose de très compliqué (bonjour les thread lock, la synchro etc.) là où l'idéal serait simplement d'écrire dans le code quelque chose du genre :

in_parallel(res1 = do_one(), res_2 = do_two());

En pratique aujourd'hui on a les langages et les outils pour pouvoir manipuler ces concepts facilement et efficacement. Quand c'est facile, quand on n'a pas besoin de gérer la synchro de threads etc. les gens sont tout à fait capable d'analyser ce qui doit être fait en séquence et ce qui peut être exécuté en parallèle. Nous mettons tous le couvert en même temps que les pâtes cuisent, on sait ce que c'est s'organiser "en parallèle", mais jusqu'à présent, dans le monde du logiciel, les outils ne permettaient pas de faire de même facilement.

Mickaël, je suis bien d'accord, il ne faut pas le mettre à toutes les sauces, mais ne pas jouer avec pour un développeur web, c'est laisser passer le train. Je dis souvent que coder en Python améliore la qualité de mon code PHP et vice-versa. Chaque langage/approche permet d'accumuler de l'expérience et finalement de choisir l'outil et l'approche les plus adaptés aux besoins.

Attendez-vous à un peu de node.js ici (j'en ai vraiment besoin pour Cheméo).

Eric said:

Ok, j'avais loupé le contexte pour "poubelle", désolé. D'autant que je suis foncièrement en accord avec ton dernier paragraphe de commentaire, c'est indispensable de jouer avec tout ce qui arrive de nouveau, pour forger ses choix et ses expériences.

Loïc said:

Merci Eric, le poubelle était provocateur pour forcer les gens à réagir et attirer le lecteur. La ficelle était grosse, mais elle a le mérite de fonctionner un petit peu.

crazyball said:

Mais qui dit JS dit que si l'user a javascript desactivé ton projet il tourne plus donc => poubelle

metagoto said:

@crazyball
Le JS dont parle Loïc est exécuté coté server.

@Loïc
Tu as tout bon. JS et JSON ont tout ce qu'il faut pour déchirer coté server.. en théorie. Avec node.js et mongodb, c'est réellement le cas dans la pratique.

Armand said:

Les frameworks Erlang sont aussi pas mal de ce côté là. Nitrogen par exemple est sympa pour un développeur web voulant élargir ses horizons. :)

Loïc said:

Tout à fait Armand et je recommande d'ailleurs l'excellent livre "Programming Erlang" d'Armstrong, le père d'Erlang, pour qui veut découvrir ce langage. Le livre est disponible en version pdf sans DRM et/ou papier.

Armand said:

Sinon, on peut lire gratuitement sa thèse de PhD <http://ftp.sunet.se/pub/lang/erlang/download/armstrong_thesis_2003.pdf> qui explique très bien la philosophie du langage.

Bravo pour tes articles en tout cas, tes contributions sont toujours intéressantes.

Raphaël said:

Tu es dans le timing puisqu'Heroku annonce aujourd'hui le support (en beta) de node.js : http://blog.heroku.com/archives/2010/4/28/node_js_support_experimental/

jpic said:

Nous avons fait pas mal de recherches sur les possibilités d'implémentation de couche metier, l'objectif étant de tirer parti des avantanges:
- du NoSQL, pouvoir ajouter/modifier/enlever des champs et relations de tout type sans altérer le schema,
- du SQL, pouvoir utiliser les bonnes vielles requettes quand meme pratiques pour exploiter les données.

Voici les détails des implementations qu'on a trouvé:
- EAV, plein de tables avec plein de requettes difficiles: de l'overbloat dans la majorité des cas (OpenGoo, Magento, eZ Publish...) http://en.wikipedia.org/wiki/Entity-attribute-value_model
- FriendFeed, une table avec une ligne par entité et des tables d'index http://bret.appspot.com/entry/how-friendfeed-uses-mysql

Nous avons opté pour une table avec une ligne par attribut et des tables d'index.

Stocker la structure JSON dans une ligne d'une table (type friendfeed) est interressant car on garde quand meme une structure; tandis qu'on est jamais certain (dans le sens "scolaire" du terme) de la structure lorsqu'on réduit une entité à partir d'une ligne par attribut.

Par exemple, si un "article" a plusieurs attributs "comments", l'attribut récupéré est evidamment une liste; tandis que si l'"article" n'a qu'un seul commentaire, l'attribut "comments" arrive donc sans etre dans une liste. En pratique, on doit faire foreach( myIterator( $article['comments'] ) as $comment ) au lieu d'attaquer directement $article['comments'] comme une array, cela ne pose donc aucun probleme.

Le probleme du stockage en JSON est la gestion des relations. Particulierement M2M. Il faudrait peut etre une table de relations qui compliqueraient les requettes c'est pourquoi nous nous sommes éloigné de cette solution.

Les tables d'index permettent de tirer profit du SQL classique en faisant deux requettes au lieu d'une, une pour selectionner les ids d'abord: select * from attributes_table where id in (select id from foo_index [...]).


Au sujet des frameworks, il est certain qu'une solution legere en PHP basée sur les "vagues concepts" KISS, DRY et NoSQL sera la bienvenue en tout cas en ce qui me concerne.

J'ignore comment vous utilisez Django, personnelement je commence les projets au moins à partir du basic_project de Pinax, et je me voie mal me priver des miliers d'applications forkables sur github. Si Django permet d'etre 8 à 12 fois plus productif qu'avec PHP, c'est selon les projets et en connaissant un certain nombre d'applications génériques, par exemple:

- django-notifications
- django-ajax-selects
- django-authority
- django-debug-toolbar
- django-extensions
- django-filter
- django-generic-flatblocs
- django-frontendadmin
- django-pagination
- django-reversion
- django-staticfiles <- vraimment indispensable
- south

Je ne me voie pas du tout faire le moindre projet django sans *toutes* ces applications pour un client final.

Tout hardcoder: c'est plus performant, mais alors en ce qui concerne la maintenance et la répartition de la charge de travail .... c'est la catastrophe.

Et franchement, j'ai pas envie de réimplementer une appli d'un projet précédent, je préfére ressortir l'appli et commencer à travailler sur ce qui rend le nouveau projet *différent* du précédent. L'usage d'un framework qui permet au moins de brancher des applis entre elles est considéré comme primordial par pas mal de devs dont vous faites peut etre parti.

J'éspere que je ne vous ai pas trop ennuyé ;)

metagoto said:

@jpic
Kyle Banker (staff de 10gen, la société derrière mongodb) a un billet intéressant sur son blog à propos de e-commerce et mongodb:
http://kylebanker.com/blog/2010/04/30/mongodb-and-ecommerce/

Dans le cadre de mongodb, les relations M2M ne sont pas foncièrement simplifiées. Ca n'est pas la solution miracle. Comme le système supporte nativement JSON (en fait un superset de JSON), d'autres outils sont à notre disposition, comme map/reduce, les operateurs atomiques, des shortcuts sympathiques etc. Ce changement de paradigme ouvre de nouvelles perspectives.

sophie viger said:

Bonjour,

J'ai en charge les programmes et le recrutement des intervenants pour l'IESA Multimédia à Paris... donc, vous imaginez bien que votre article m'a beaucoup intéressé, d'autant que j'étais en pleine réflexion : symphony vs RoR pour nos étudiants !
Pourriez-vous me contacter par mail, car j'aimerais, si cela ne vous ennuie pas, vous poser quelques questions !
Merci beaucoup

Sophie Viger

Voice your ideas

It is painless and I try not to kill electrons in the process.


Your email is required but will not be shared nor displayed.


Do you think your comment will force me to write even better stuff next time? If so, you simply rock.


Logo of Plume CMS