JQuery toujours pas pour moi

Publié le 05/09/2012

Suite à un vieux post qui s’est terminé par une horde de pas mal de fans de jQuery insultants, j’ai évité de continuer à commenter et je décide de refaire un article. Deux ans se sont écoulés, et ma vision de jQuery se déteriore de plus en plus… J’ai admis certaines critiques, mes exemples n’étaient pas forcément les plus adéquats et mon entrain à défendre un point de vue n’a pas été suivi par une explication claire. Du coup, voici un point de vue plus “technique” et plus poussé sur le “pourquoi je n’aime pas du tout jQuery”

Pour appuyer mes remarques et mon avis, je vais me baser sur des discussions que j’ai eut depuis 2 ans. Que ce soit après ma conférence donnée sur JS ou avec des collègues, j’ai noté les remarques, et je vous redonne texto ce que j’ai répondu ou ce que j’ai tenté d’expliquer.

En plus de ces remarques, je vais vous montrer aussi les points principaux qui me font vraiment une poussée allergique à ce “framework” Javascript.

Sémantique

Commençons par ce qui m’orifie le plus, à savoir cette sémantique qui me fait palir.

Prenons un exemple tout bête: $('#element').load(handler)

Non mais vous plaisantez ? quand je lis ça je me dis que “load” ça charge un truc. Bha non ! là c’est l’évènement “onload” qui appelle le handler. Une sémantique pareille me choque vraiment, surtout que:

//pris de la doc... $('#result').load('ajax/test.html');

Ce coup-ci load charge bien un truc… la page “ajax/test.html” est récupéré via un XHR (XHttpRequest, et pas “Ajax”, on va y venir…) et le contenu est inséré dans l’élement…

Vous pouvez me dire ce que vous voulez, utiliser un nom de méthode pour deux opérations qui n’ont rien à voir, c’est absurde et pas propre. Vous en voulez un autre, bougez pas.

La méthode “click” par exemple. En premier lieu, moi quand je lis ce nom, je me dis “tiens c’est cool, une fonction qui simule un click”. Et j’ai pas tort en fait. Car si je fais:

$('#toto').click()

alors je simule un click. Je ne fais que répéter la doc:

“In the third variation, when .click() is called without arguments, it is a shortcut for .trigger(“click”).”

Mais si je mets un handler en paramètre, alors tout le comportement est différent, car dans ce cas la fonction “click” enregistre un “event listener”.

Deux comportements purement éloignés, qui sont bien séparés dans tous les autres framework JS. On définis plutôt une méthode “onclick” et “click” qui font deux choses bien distinctes.

Terminologie hasardeuse

jQuery a vraiment un souci avec les termes. Quand je lis le code qu’on pond, j’ai l’impression de parler comme un petit débutant qui connait rien au HTTP, HTML, CSS et JS… je vous explique.

Savez-vous ce qu’est un CSS ? Cascading StyleSheet, ce qui signifie “Feuille de style en cascade”. Autrement dit, une CSS est une arborescence qui définit des styles pour des éléments dissociés par des attributs (class, type…), des identifiants (id), des états (active, hover, visited…) et en les repérant par leur hiérarchie dans le DOM. C’est un standard clair, qui évolue.

Chaque propriété d’un élément repéré est un **style**. On est d’accord ? je l’espère… parce que les auteurs de jQuery ont une autre définition. Pour eux, un CSS est un style… Si si…

Je vous montre:

$('.class-element').css('color','red')

Vous me direz “ouais tu pousses, en fait on change la CSS pour les éléments de classe classe-element “. Non ! car:

$(this).css('border','1px solid black')

ce code change le **style d’un élément unique**, et si ça suffit pas, regardez avec Firebug ou la console de Chrome/Chromium pour vous rendre compte que l’attribut touché est “style” et **non pas la feuille de style**. Je chipotte ? si aujourd’hui vous voyez un framework dans un autre langage, pour une autre technologie que le web, je vous assure que vous seriez choqué.

Ici, on dit que “CSS” permet de modifier le style de l’élément. C’est juste une erreur me diriez-vous. Et bien non. Les auteurs de jQuery ont vraiment du mal avec les terminologies, car pour eux on peut faire du “Ajax synchrone” avec du JSON.

Rappel: Ajax = Asynchroneous Javascript And Xml

Dire que vous faite de l’Ajax synchrone, c’est comme dire que vous faites de la photo avec une toile, des peinceaux et de la peinture… c’est vrai quoi, la photo et la peinture c’est exactement pareil, on ne va pas chipoter hein !

Alors pour reprendre les choses clairement, si vous faite un appel HTTP en javascript, que ce soit synchrone ou non, avec du JSON ou non… c’est ce que nous appelons une “requête HTTP”, ou “Http Request”. C’est d’ailleurs pour cela que l’objet standard JS se nomme XHttpRequest (on dit aussi XHR), et que les autres frameworks JS l’appellent de la même manière… Mais apparement, jQuery veut se démarquer avec des termes erronnés. Ou alors, ce que je pense fortement, c’est qu’à la base jQuery faisait du HTTPRequest en mode asynchrone par défaut, et qu’un jour les développeurs se sont rendu compte qu’on pouvait faire des appels synchrones. Comme pour “css”, ils ne se sont pas posé la question et ont ajouté l’option “synchrone” à une terminologie qui veut dire “asynchrone”: Ajax.

Ce qui me choque, c’est que jQuery est arrivé après Prototype et Mootools, et eux ont fait cette distinction. Sauf qu’au lieu de respecter un standard de dénomination, les auteurs de JQuery ont décidé de prendre des termes “bateaux” pour monsieur Michu qui décide de développer sans connaître Javascript à la base. On y reviendra après.

Vous me trouvez sarcastique, je ne m’en cache pas. C’est pas aggressif, c’est juste que je tente de défendre ces idées depuis des années et que je reste dépité à entendre des gens défendre des erreurs pareils. Bref, continuons.

Sélecteurs illogiques

J’adore les selecteurs. Non là je ne suis pas ironique ! Que ce soit sur Prototype, jQuery, Mootools, etc. l’utilisation des sélecteurs me plait.

Mais… là où jQuery m’enrage, c’est cette utilisation de “\$” pour tout et n’importe quoi. Et surtout qu’il fait une chose infâme quand on bosse sur du DOM, laissez-moi vous expliquer.

On m’a par ailleurs sorti: “attend mais Xpath tu n’aimes pas ?” Mais bien sûr que si ! Je me répète, j’adore les selecteurs, mais encore faut-il que le framework sache les utiliser dans les règles. Je vous donne un exemple tout bête. Un élément peut avoir un “id” (identifiant) qui **doit être unique**. En JS pure, on utilise alors la fonction “getElementById” qui récupère **un et un seul élément**, c’est-à-dire l’élement qui a cet ID.

Avant de passer à la suite: oui merci je connais querySelector et querySelectorAll qui utilisent la même syntaxe que jQuery pour les sélecteurs, et je n’aime pas…

Revenons à mon souci: Si deux éléments ont le même ID, alors c’est une erreur de votre part. Vous devez corriger le DOM.

Sauf que voilà… JQuery ne sait pas ce que c’est que de retourner un seul élément. Il retourne toujours une collection, que l’élément soit unique (via un id) ou pas.

Alors comparer cela au comportement de Xpath, excusez-moi mais ça me fait mal ! Car Xpath retourne un élement unique et non une collection si vous sélectionnez un élément qui doit l’être. Point barre. Et querySelectorAll fait pas mieux là dessus… Cherchez pas à me vendre que le code suivant est normal:

var uid = $('#id-unique')

Ici, “uid” est une collection, avec un seul élément à l’intérieur. Inutile de me retourner une collection.

Tiens je reviens sur ce que j’ai dit, finalement querySelector est pas bête, car lui il me retourne un seul élément, et querySelectorAll me retourne une collection, je sais donc choisir entre deux cas. Ho mais attendez…

Prototype et Mootools (pour ne citer que ceux ci) font une distinction importante entre une collection et un élément, ils ont utilisé une fonction séparée pour cela:

-\$ pour un élément identifié par un id -\$\$ pour une collection, sélectionnée via des selecteurs CSS

Marrant hein, 7 ans plus tard les moteurs JS récents utilisent aussi deux méthodes de sélections: querySelector et querySelectorAll.

Mais attendez la suite, vous allez voir que pour jQuery, un élément ayant un id n’est pas forcément unique, selon le cas. C’est juste la section suivante.

4 méthodes, 2 comportements, aucune logique DOM

Qu’est ce qui est passé par la tête des développeurs de JQuery quand ils ont développé les méthodes “find”, “children”, “parent” et “parents” ?

Tout d’abord, le truc qui me choque: find et children. Le premier trouve tous les déscendants d’un élément selon un sélecteur, alors que children fait pareil mais pour **seulement le premier niveau**. Admettons, ça ne me choque pas trop jusque-là. Mais par conséquence, pourquoi “parents” peut remonter de plusieurs niveaux ? On a deux méthodes inversement liées (parents, enfants) qui n’ont pas la même logique de sélection.

Et toujours avec cette fichue collection par défant, parent() vous retourne un seul élément (normal hein) mais dans une collection…

Si ça n’était que cela, je dirai “ok, pourquoi pas, après tout c’est une dénomination”. Mais là où ça marche plus, c’est quand je vois ça:

<!-- on fait n'importe quoi -->
<span id="foo">
    <div id="toto">toto 1</div>
    <div id="toto">toto 2</div>
    <div id="toto">toto 3</div>
    <div>
         <span id="toto">un span toto 4</span>
    </div>
</span>

On est d’accord que c’est une erreur, on a 3 fois le même “id”. JQuery est pas trop débile et sait que “\$(’#toto’)” retournera un seul élément, en l’occurence le premier, et à la limite ça me convient.

Mais par contre, avec children, on en a 3 !

Testez: alert($("#toto").length) alert($("#foo").children("#toto").length) alert($("#foo").find("#toto").length)

Vous pouvez voir ici: http://jsfiddle.net/metal3d/9KDA4/1/

C’est quoi cette implémentation ? trois cas possibles ?

On se retrouve avec des comportements illogiques.

Tout passe par \$, merci la POO

Et pour revenir au cas du fameux “\$“, on va prendre un exemple de handler de click. Dans cette méthode, “this” correspond bien à l’élément cliqué, mais pas “\$(this)” qui lui est une collection contenant un seul élément (celui qui est cliqué)… Cela a une impacte sur la logique: puisque le handler est appelé par jQuery, il y a peu de raison (perso j’en vois pas) pour que “this” ne soit pas au moins l’objet jQuery contenant l’élément. Parce que forcer l’utilisateur à taper “\$(this)” pour avoir les méthodes spécifiques au framework… je ne vois pas l’intérêt.

Et en en vient à ce qui me dépite le plus…

Ce fichu “\$” sert à tout dans jQuery: sélecteur, espace de nom, bind d’évent du document… tout y passe. Du coup, quoique vous fassiez, créer un XHR, une collection, une collection, c’est un objet “jQuery” (mapé en \$).

Impossible de faire des classes, et ne venez pas me parler de \$.extend parce que tout développeur qui a bossé avec des langages objets ne peut honnêtement me dire que cette méthode est digne de ce nom.

Alors que Prototype, Mootools, Dojo, etc, vous permettent de bosser avec des classes, jQuery vous demande de faire du code pas beau pour tenter de faire des héritages, des proxy et on oublie l’implementation. Impossible de classifier des objets par classe. Et c’est là que le “code less, do more” me fait sourire, car pour faire du code un peu sérieux, on est obligé de coder beaucoup plus pour contrôler tout le code, alors que JS est un langage Objet et qu’on pourrait faire du code plus propre, plus pro, et maintenable.

Franchement, regardez du code dans d’autres framework, par exemple en Mootools (que j’aime beaucoup):

$("element").addEvent('click', function (){ this.setStyle('color','red') });

Comprennez bien que dans Mootools, Prototype, etc. la fonction “\$” ne sert que de sélecteur ! l’espace de nom est un élément du document. Cela permet de faire des classes, des implémentations, sans avoir des “\$” partout.

Masquage du JS

Je reviens à M. Michu qui code en JQuery sans connaitre le javascript. D’une, **non je ne critique pas tous les utilisateurs de jQuery en pensant que ce sont des débiles**. Que ce soit bien clair, jamais je n’ai pensé cela ! On me l’a ressorti ce matin, ça commence sérieusement à m’aggacer que “du moment où on a une vue critique d’un framework” (surtout que, désolé, mais je connais très bien JS et d’autres frameworks) alors ses utilisateurs se voient automatiquement pris pour des cons.

Ce que je critique, ce n’est pas le fait de ne pas connaître JS. C’est le fait que le framework masque fortement le langage. C’est le cas pour beaucoup de frameworks de pas mal de langages. Je vise particulièrement PHP et eZ Publish qui ont vraiment tendance à sucrer le langage et forcer les intégrateurs à coder dans les templates.

Le vrai souci ici, c’est que la puissance du langage est littéralement court-circuitée par le framework. C’est beaucoup moins le cas pour Prototype par exemple qui a gardé (justement) les notions de prototypage de classe. Mootools a une syntaxe très claire de création de classe et garde ses méthodes proches du langage d’origine.

Or, avec jQuery, vous ne faites pas de JS, mais du jQuery. Et c’est selon moi très dommage.

Une note positive quand même ?

Mais évidemment ! Si je suis aussi “agressif” envers jQuery c’est surtout parce que beaucoup de projets pro utilisent ce framework sans avoir de réflexion a priori. jQuery est un excelent framework pour des interfacages rapides, monter un ou deux caroussels et utiliser des systèmes “basiques”. C’est parfait pour un blog, un site non complexe et ne demandant pas beaucoup d’interactions. Parfait parce que **simple** et ne demandant pas beaucoup de code pour une utilisation standard.

Mais si votre interface a besoin d’évolutivité, de maintenance, demande beaucoup de code pour interfacer dynamiquement le site, alors utilisez un framework plus orienté POO, plus professionnel et moins gadget.

jQuery a eut le mérite de proposer une implémentation vraiment facile à utiliser, rapide à mettre en oeuvre et ne demandant pas de lire de la doc constamment. Mais avant de choisir par défaut jQuery parce que “vous le connaissez bien”, testez d’autres frameworks et faites-vous une idée.

Le bilan de 7 ans à utiliser 5 frameworks m’a donné cette vision:

-jquery != js, = gadget super simple et efficace en mode standard -prototype, mootools = POO, fiable, propre et modulaire -dojo = implémentation supra modulaire, proche de JS standard (oui, innerHTML ça marche hein) -extJS = on se tape des UI pour faire une application, pas un site

Mais:

-tous les frameworks ont tendance à faire oublier la puissance de JS et du DOM -trop de développeurs oublient que la plupart des UI qu’ils font sont faisables en CSS + un JS basique simple -un framework JS ne doit être utilisé que si, et seulement si vous perdez du temps à le faire en JS simple

Maintenant, vous pouvez penser ce que vous voulez, j’en ai discuté lors des conférences que j’ai données, et je sais que je ne suis pas du tout le seul à penser que jQuery devrait franchement être utilisé à moindre mesure… et que trop de développeurs ne s’intéressent pas assez aux autres technologies. C’est mon opinion, voilà tout.

comments powered by Disqus