Mais qu’est-ce que vous avez fait de Javascript ?

Note préliminaire : cet article est avant tout un recueil de mes opinions. Il ne s’agit pas de faits, ou d’éléments soigneusement étudiés, mais plus d’irritations, d’incompréhensions. (Vu que cet article est en train de devenir mon plus lu, je préfère baliser le terrain)

Je viens de finir un bon paquet de développement Javascript « full-stack » avec Nodejs, Vuejs et tout un tas de trucs. Et franchement,

(oui, il va y avoir un paquet de tweets, parce que j’ai eu l’occasion d’en parler)

Mais qu’est-ce que vous avez fait au langage ?

a7fc014bf8488b37d60ed7dc6c76acbff5d3fb7491ff3cbd302a4a9a4743ef14Quand je faisais du Javascript, avant, on avait un chouette langage fonctionnel salement déguisé en Java par le biais d’un marketting stupide. Et un jour, V8 est arrivé, et comme l’héritage par prototype, c’est pas cool, ES5 et ES6 se sont succédés à un train d’enfer pour apporter toutes les folies des langages orientées objet : import, héritage, interfaces, closures, théoriquement, vous avez maintenant tout ça.

Le cas particulier de l’import

Ca marche comment l’import ? En Javascript classique, ça marche facilement avec requirejs (la doc est claire, et le besoin assez simple). Avec ça, écrire une application un peu complexe, c’est quand même raisonnablement facile (je le sais, je l’ai fait). Mais en ES6, si vous êtes côté serveur (dans Nodejs, kwa), vous écrivez

const expect = require('expect.js')

Mais côté client, vous écrivez

import localForage from 'localforage'

Mais c’est vraiment génial, cette idée de NE PAS UTILISER LA MEME SYNTAXE DANS DIFFERENTS ENVIRONNEMENTS ! Je ne sais pas combien de langages précédents ont eu cette idée … douteuse. Tout ce que je sais, c’est que je n’en connais aucun.

Non mais static, c’est static ou bien ?

Oui, parce que bon, superposer les concepts Java/C# sur une base Lisp, ça donne parfois des résultats curieux.

Du coup, quand vous créez une classe comme ça

class CaVaMarcher {
	static uneFonction() {
	}
	
	static uneAutre() {
		this.uneFonction()
	}
}

Est-ce que ça marche ? Eh bien je n’en sais rien. Mon code me dit que oui, mais ma tête me dit que non. PARCE QUE STATIC AVEC THIIS C’EST ENCORE UNE IDEE GENIALE ! A la décharge des fous qui ont créé ES5/ES6, this a toujours été un problème du Javascript.

Mais qu’est-ce que vous avez fait au build ?

Parce que bon, jusqu’à node/npm, livrer un projet JS, c’était pas super dur : tu prends tes fichiers, si tu es audacieux tu les minifie (mais en vrai ça n’est pas si important si tu caches bien ton JS, ou que tu utilises un CDN), tu les mets dans ton WEB-INF/resources (en Java), et BAM, c’est servi.

Webpack de l’enfer

escapefromhellgraphicEn 2017, comme tu fais de l’ES6, mais que ton navigateur ne le supporte pas forcément, tu passes par webpack pour le transformer en honnête Javascript.

Et dans quel enfer tu t’enfonces ? A côté de ça, générer les interfaces des EJB 1.0 avec ejbgen c’était de la rigolade. Que je vous raconte. Le truc génère un gros fichier Javascript (5 Mo pour notre application) à partir du paquet de code, d’images, de CSS (compilé depuis des préprocesseurs, parce que franchement, la syntaxe CSS n’est pas terriblement lisible – qu’ils disent). Pour ça, il faut configurer ça avec un fichier webpack.js à la syntaxe … Tellement merdique. Regardez donc cet exemple. C’est un cas vraiment super simple qui ne fait pas grand chose de sophistiqué. Et pourtant, c’est déja la merde non documentée. Alors quand il faut ajouter des trucs comme vuejs (j’en reparlerai, pas de panique), ça devient incroyablement tordu.

Surtout avec les histoires de sourcemap (qui sont un authentique exemple de complexité accidentelle) qui sont loin de marcher aussi bien qu’imaginé.

Du coup, webpack, ça marche, mais franchement, ça a un côté terrifiant de complexité inutile dans le concept et dans l’implémentation. Heureusement, le reste du build cache ça.

Non mais ce build JS

npm de merde

dessin-de-merdeLà ça m’énerve vraiment. Quand ces folies de build ES5/ES6 ont commencé, et que les besoins de gérer un cycle de vie et des dépendances se sont posés, il me semble que les Javascripteurs auraient pu, à défaut d’utiliser, tout au moins copier les idées de maven, par exemple, ou d’autres build tools du monde Java (ou d’autres, mais je ne les connais pas). Parce que franchement, les mecs qui ont créé npm (qui a fourni le format canonique du package.json) ne se sont pas trop fait chier : une liste de dépendances, et une map associant des noms de commandes, et c’est marre. Pareil pour la récupération des dépendances : les mettre dans un dossier node_modules dans le projet, sans trop se soucier de la version téléchargée, c’est une PUTAIN D’IDEE DE MERDE.

Yarn de super-merde

800px-kin_no_unkoA cause des défauts invraissemblables de npm, les mecs de facebook ont créé yarn qui « ccorige le problème des versions incorrectes ». PUTAIN MAIS ILS NE POUVAIENT PAS ETRE AMBITIEUX ? Parce que bon, d’accord, ces histoires de dépendances incertaines, c’est un problème. Mais il y en a d’autres.

Comme par exemple le fait que les commandes soient dans cette saleté de map, et soient en fait des exécutables système (qui doivent donc être dans le PATH, et ne marchent donc pas sous Windows – gg les gars).

Ou comme le fait qu’il n’y ait aucune espèce de build standard, et qu’il faut donc tout réécrire dans chaque projet.

Ou comme le fait qu’il ne soit pas possible de définir de modèle de projet, ou de modularisation du build.

Franchement, yarn, c’est bien de l’esbrouffe.

Et ces frameworks de merde

wrong-tool-pizzaParce que bon, angular, c’est l’horreur, tout le monde le sait, ça a été conçu par des mecs qui avaient trop fait de développement JavaEE et en avaient perdu l’esprit. React, je peux pas en dire du mal (mis à part le fait que si tu t’en sers sans la surcouche de Redux, t’as l’air d’être dans la merde, puisque tout le monde te dit qu’il faut utiliser Redux).

Du coup, forcément, tu suis tout le monde comme un mouton, et tu prends vuejs avec l’impression d’être un putain de révolutionnaire. Bon, c’est dommage pour toi, parce que Ractivejs, c’est comme vuejs, mais en mieux (si si, en mieux).

D’abord, t’as pas le concept complètement con de fichier .vue dans lequel tu mélanges le HTML, le Javascript, et le CSS. Parce que qu’est-ce que vous avez PUTAIN DE PAS COMPRIS DANS LA SEPARATION DES RESPONSABILITES ? Je veux dire, quand t’écris ton composant, tu passes pas ton temps à modifier les trois en même temps, si ? En bonus, le fichier .vue, ben ton navigateur ne le comprend pas. Du coup, tu dois aller modifier ton webpack.config.js qui était déja bien merdique pour utiliser le vue-loader, qui fout un peu la merde avec le sass-loader. Bon, mais ce problème de build n’est en fait qu’un épiphénomène.

Ben oui, parce que vuejs fournit peut-être des « composants », mais il faut encore que tu utilises un framework CSS, sinon tu vas galérer avec les resets CSS. Du coup, tu te rajoutes Bulma (oui, le nom est merdique pour les recherches dans Google) par exemple, mais tu dois aussi l’intégrer dans webpack parce qu’il est fourni en SCSS (re-argh).

Et bien sûr, c’est quand tu ajoutes Bulma, vuejs, et toutes tes dépendances, que ton fichier JS généré atteint les 5 Mo. 5 Mo, tout ça parce que tu ne veux pas que l’utilisateur attende au démarrage de ta page. Non mais qu’est-ce que c’est que cette merde ? Tout ça pour un PUTAIN DE SITE MOBILE. Comment vous croyez que ça peut marcher avec une connexion un peu faible ? Ben mal. Très mal. Trop mal.

Et ce offline de merde

pas-de-signal-panneLà, pour le coup, c’est chaud, mais je veux bien comprendre le concept. Quand ton navigateur est déconnecté, pour pouvoir utiliser l’application web, tu dois stocker toutes tes données dans le cache local.

Mais là, tu fais comment ? Tu utilises localForage directement ? Ou tu passes par des web workers ? Et là, j’atteinds ma limite, donc je ne peux pas râler en majuscules.

Mais pour tout le reste, clairement, le monde Javascript déconne à pleins tubes. J’espère bien que ça changera, parce que là, c’est super pour que les sociétés de service fourguent des consultants qui connaissent juste le framework à la mode. Mais honnêtement, c’est pas comme ça qu’on produit du logiciel durable. Mais est-ce que ça fait partie des besoins des clients ? Je n’en sais rien.

Mais du coup tu vas refuser de faire du Javascript ?

Non, parce que dans les bonnes conditions (donc sans node, sans webpack, sans framework aux idées à la con), développer une appli web Javascript (par exemple avec requirejs, Ractivejs, et un peu d’axios pour les requêtes Ajax, le tout en Javascript classique) est assez plaisant, et surtout très simple. Par contre, les outils actuels du développeur full stack Javascript sont, à mon sens, à la fois insuffisants et conceptuellement incorrects.

Publicités

Vite, un chtijug !

Je me demande si je n’ai pas déjà utilisé ce titre …

En attendant, hier soir, c’était chtijug spécial quickies.

HTTPS Everywhere avec let’s encrypt

Le HTTPS c’est mieux pour la confidentialité des utilisateurs. Let’s encrypt est une autorité de certification, dont le client essentiel est certbot.

certbot

Tourne sur n’importe quel Unix (oui oui). Il y a des plugins pour tous les serveurs web, même sur le Raspberry.

Démonstration avec un site Apache

S’ensuit une jolie démonstration avec des poneys en ascii-art. Et tant mieux, parce que certbot a une interface ncurses ! On note tout de suite les problèmes classiques liés à du https : le mixed content (images ou scripts chargés en http, …). Je note également le point « magique » de Let’s Encrypt : obtenir un certificat à la volée, c’est quand même vachement plus rapide que de le réclamer physiquement à un service de sécurité.

Validation du certificat

La partie intéressante de Let’s encrypt, c’est le mode de génération de certificat. Plutôt que d’utiliser la méthode traditionnelle avec échange de mail, ils reposent sur l’exposition d’un challenge en http sur le site pour lequel on veut un certificat. C’est assez malin, car plus facilement automatisable. Et j’imagine que certbot doit pouvoir automatiser ça

Démonstration avec nginx et webroot

Histoire de montrer les capacités de certbot, on refait la démo, mais avec une configuration manuelle, pour nginx.

Intérêt ?

Le certificat est renouvellé automatiquement tous les 90 jours ! Du coup, plus de problème d’expiration. Et ça, pour les noobs de la sécurité comme moi, c’est vraiment cool. Un point important à noter : Let’s encrypt ne fournit que des certificats de classe 1, donc avec une sécurité « moyenne ». Les classes 2 et 3 impliquent des vérifications physiques, qui sont évidement manuelles.

Point bonus : il y a une interface permettant de révoquer les certificats depuis le site de Let’s Encrypt, ce qui provoquera sans doute leur renouvellement automatique.

Ce que la revue de code m’a apporté

Julien commence par nous raconter sa vie de jeune développeur. Et, personnellement, je me reconnais mal là-dedans :

  • la fierté du code produit
  • la propriété du code (c’est le code de Julien)
  • Et enfin, il veut que son code soit beau longtemps

Du coup, ils ont mis en place chez Axa des revues de code avec des rôles identifiés pour limiter les procès en sorcellerie. Malheureusement, j’ai peur que ça ne suffise pas. Du coup, il faut apprendre plusieurs choses (qui, il me semble, font partie de l’expérience du développeur). La première étant évidement de faire preuve de bienveillance envers ses collègues, le fameux « dur avec le code, doux avec les gens ».

Axa consomme environ 5% de son temps à faire de la revue de code. C’est assez peu, vu que ça permet de détecter des bugs (en plus d’assurer une cohérence stylistique des livrables).

A priori, il faut environ 3 mois pour que les revues soient « apaisées ».

A la réflexion, il y a à mon avis quelque chose de complètement biaisé dans le fait que le développeur vienne présenter lui-même son code à un procès en sorcellerie. Il vaudrait sans doute mieux que le code soit défendu par un « avocat » sans que le développeur à l’origine du code puisse être reconnu. Parce que, comme je le dis toujours, le code qui est dans Subversion/Git n’est plus ton code, c’est celui de l’équipe. Et c’est ce qui le rend magiquement sale.

lunrjs

lunrjs est un portage de Lucene pour javascript, utilisé chez Decathlon. Et sur le site de Decathlon, actuellement, quand on change un filtre de recherche, la page est visiblement rechargée (ce qui n’est pas terrible en termes de performances). Un portage, mais un peu restreint, puisqu’on perd par exemple les recherches de termes approchants.

A noter qu’actuellement, le catalogue produits de Decathlon est hébergé en SAAS, ce qui est … osé, je trouve.

Cela dit, je n’ai pas trouvé ça si impressionnant. Parce qu’il existe déja des tonnes d’API javascript pour exploiter le local storage « correctement ». En fait, le seul intérêt de lunrjs, c’est de compléter les recherches disponibles dans Lucene pour les déconnexions, mais je trouve le cas d’utilisation assez rare pour ne pas investir spécifiquement dessus. A mon sens, travailler sur une vraie API client/serveur dans le navigateur permettrait plus facilement d’attaquer ce type de problème. Sauf, bien sûr, si l’objectif du projet est précisément d’étendre Lucene, mais c’est plus de l’ordre du patch que de l’évolution en profondeur.

Cerberus

Donc, cerberus est un outil de test fonctionnel automatique. Des outils comme ça, il y en a … déjà … des tonnes. Alors pourquoi La Redoute s’est lancée dans cette guerre des tranchées ? Comme d’hab, l’hubris (autrement dit « il n’existait pas de solution correspondant à leur besoin »). Cerberus se place donc entre les différentes équipes, pour fournir un référentiel commun. ce qui implique également que les tests puissent être décrits par les fonctionnels ou les développeurs. Et comme un outil comme HPQC, il offre tout un tas de fonctionnalités, comme le support multi-technologies, multi-langues, multi-environnements l’exécution adaptative des tests, la génération de rapports ou l’intégration dans les outils de développement du SI (IC, bug tracker, …).
Bon, j’avoue, j’ai décroché lors de la démo. Parce que vraiment, on est face à de l’outil de test fonctionnel très haut niveau, où les étapes peuvent être effectuées manuellement ou automatiquement. Ce qui ne m’inspire qu’une chose : ces outils ne sont pas faits pour le monde d’aujourd’hui, mais pour les bonnes grosses applications traditionnelles des entreprises qui ont encore des équipes dév, fonctionnelles, test, différentes, et des processus de livraison longs et lourds. Dans ce cadre, j’imagine que ça doit marcher. Mais dans le cadre hyper-mouvant du web de 2016, je ne suis pas sûr que ça bouge assez vite.

Conclusion

Je peux paraître un peu dur avec certains des talks, mais ça n’est pas mon but. Le contenu ne m’a peut-être pas autant intéressé que les orateurs l’auraient souhaité, mais ça n’ôte rien à leur prestation. Les quatre présentations étaient en effet bien préparées, construites, bien organisées. C’est juste que chaque auditeur met ses propres filtres sur les sujets qui lui sont présentés … Bravo encore au chtijug qui arrive toujours à trouver des choses intéressantes à nous présenter (eh oui, ça n’est pas parce que ça ne m’a pas plu que ça n’était ps intéressant).

Pas de chti jug sur Typescript pour moi

Ce soir, c’est chtijug sur Typescript. Et en plus, le lieu a l’air sympa.

Pas parce que je n’aime pas Cyril et ses amis, bien au contraire, je trouve le boulot du chijug vraiment chouette.

Mais plutôt parce que … comment dire … tout cet écosystème Javascript me fatigue à un point fou.

Je vous explique.

J’ai fait ma première page web avec du Javascript en 1999 … ou 2000. Bon, la wayback machine a une version datant de juillet 2001. Enfin bref. A l’époque, faire du Javascript était un sale boulot.

Heureusement, jQuery a tout changé. Et pendant quelques années, faire du web dynamique était raisonnablement simple conceptuellement et techniquement.

Et puis un jour, l’apocalypse de la sur-architecture s’est pointée sous les traits de nodejs. Je ne vais pas refaire l’article contre nodejs, parce qu’il suffit de regarder quelques twits de Mario Fusco ou Sam&Max pour comprendre

Et c’est quoi le rapport avec Typescript ?

Pour être honnête, Typescript n’est pas une solution, mais un élément du problème.

En effet, de mon point de vue, les langages modernes ont été créés pour permettre aux gens d’être plus productifs que l’assembleur ou le C, par exemple. Seulement, et au risque de choquer mes camarades Javaistes, le Javascript n’est pas ce genre de langage.

Non.

Comme l’écrivait Douglas Crockford il y a … un moment, le javascript n’est pas le langage qu’on croit. Et franchement, une fois qu’on comprend que le Javascript est un langage fonctionnel s’exécutant dans un environnement peu commode, il se passe une certaine épiphanie qui permet de mieux en comprendre la réelle simplicité. Une simplicité qui rend des monstruosités comme Angular, React, ou Typescript, aussi pratiques qu’un 38 tonnes en ville.

C’est aussi pour ça (en plus de ne pas assister à une conf sans doute intéressante sur un langage qui doit sans aucun doute avoir de bons côtés) que j’ai décidé de ne plus me lancer dans des projets front-end en utilisant autre chose que des bibliothèques simples (voire élémentaires) qui remplissent proprement une fonction simple et claire. Des outils comme

  • RequireJS
  • RactiveJS
  • jQuery
  • underscoreJS

Et sorti de là, comme disait il y a bien longtemps mon prof d’info, point-barre. Du coup, forcément, ce talk sur Typescript présentait un problème d’intérêt fondamental : comment diable pouvais-je m’intéresser à un langage dont la finalité actuelle est précisément de faire quelque chose qui me répugne au plus haut point ?

#devoxxfr – l’ISS sur mon portable

Comme le types algébriques est annulé (le speaker s’est perdu dans Devoxx), on passe tout de suite à l’ISS sur le portable d’Audrey Neveu.

Et à priori, il sera question d’ionic … déjà vu au chtijug il me semble. Et pour alimenter ionic, Audrey va utiliser streamdata.io (entreprise chez laquelle Audrey est évangéliste). Comme ionic est déjà vu, je vous le laisse de côté …

Cela dit, pour les données, il faut faire du temps réel. Pour faire du temps réel, on va semble-t-il prendre du server-side-events, solution sur laquelle se base streamdata.io. Et manifestement, c’est une solution qui fait tout un tas de trucs bien malins.

Et c’est parti pour le dev ionic/cordova/angular/streamdata/…
Et ça va très très vite jusqu’à la fin .. qui montre bien la position de l’ISS en temps réel.

Cela dit, je retiens évidement l’intérêt de streamdata (que je ne connaissais pas) et de ces server-sent-events. ca a l’air bien pratique pour faire de la notification en HTTP plutôt que de l’échange bidirectionnel façon websocket.

#devoxxfr Boucles de feedback du développeur

Et donc le but du talk, c’est de permettre au développeur de rester dans sa zone de concentration … en évitant les pertes de temps liées au redéploiement.

Donc pour être rapide, ils vont utiliser peut-être un tomcat en prod, mais surtout en jetty intégré avec maven, et c’est bien parce que ça démarre très vite. Et pour être honnête, j’ai personnellement déja joué avec le plugin maven-jetty-plugin et les scaninterval … Mais je n’avais pas réussi à lui faire prendre en compte les modifications de code source. Et puis, pour être honnête, on n’est pas encore au niveau de …. Wisdom \o/.

Alors avec maven-jetty-run on peut relancer l’appli. Mais pour les tests, on fait comment ? J’imagine qu’ils vont me parler d’infinitest … bingo ! C’est vrai que je sais qu’il existe depuis …. qu’Eric Lefevre en a parlé il y a bien longtemps.

Et c’est tout pour le serveur. Passons maintenant au client. Notez qu’encore une fois, quand je change mon code Javascript dans Wisdom, il est relinté, recompressé, et peut-être même retesté à la volée. Mais quand même … Il y a aussi des outils qui permettent de modifier le JS dans le navigateur, et de le voir modifié dans le projet source.
Avec Chrome dev tools, on peut créer des « workspaces » qui associent à des fichiers fournis en HTTP des fichiers sur le filesystem. C’est bien, parce qu’on peut directement bosser dans le navigateur avec tout son outillage, et avoir les modifications effectuées sur les fichiers source. D’un autre côté, avec grunt browserSync, on peut demander au navigateur de se rafraîchir. Et c’est assez génial, puisque la page web se rafraîchit très très très vite. Franchement, j’aimerais bien voir ça dans …. Wisdom ! En plus, browserSync, permet de synchroniser la navigation entre plusiurs navigateurs. Et évidement, c’est incompatible avec les workspaces : le workspace modifie le fichier, browserSync recharge la page, le workspace détecte à nouveau la modification, …

En bonus, côté Javascript, on peut aussi faire des tests avec Karma/Jasmine. Et on peut également mettre un watcher … du coup le test sera rejoué. Et pour ne pas regarder la console, Karma a un plugin growl … Ca, ça fait plaisir !

isomorphique de quoi ?

La semaine denrière, c’était chtijug.

Oui, je suis un peu en retard, mais c’est pas trop grave, parce que pendant ce temps, l’orateur a eu le temps de mettre ses slides sur internet.

Session un peu particulière, en particulier avec son titre assez … ronflant : « réalisation d’applications isomorphiques avec spring boot, React et Nashorn ».

En vérité, c’est beaucoup plus simple à décrire que ça : vous savez que votre JVM intègre, et depuis un moment, un interpréteur Javascript ? Non ? Eh bien c’est pourtant le cas, grâce à la JSR 223 (l’une des meilleures à mon avis), qui permet de lier sous une interface commune la plupart des interpréteurs pour la JVM. Ainsi, exécuter du javascript (grâce à Rhino ou Nashorn), du Python (grâce à Jython), du … Groovy (funky baby) ou même … oui, même … du Java interprété (grâce à Beanshell) est vraiment très facile.

Donc, la présentation de Sébastien utilise cette percée, et la disponibilité en masse de frameworks javascripts, pour remplacer le beaucoup trop vieux et trop moisi rendu JSP par un rendu fait grâce à mustache (que je connais bien grâce à Ractive) ou React. Je ne vais pas vraiment m’éterniser sur React, parce que franchement, le JSX, c’est la pire idée à laquelle je puisse penser. En revanche, conceptuellement, c’est assez élégant.

Je m’explique.

Quand vous faites votre application web, vous avez votre joli modèle Java bien typé. Et c’est bien. Mais, au moment où vous faites le rendu dans votre JSP (ou votre template thymeleaf si vous utilisez Wisdom, par exemple), vous passez dans le monde moche et pénible du string typed. Tout est string, et vos objets Java n’ont plus d’autres intérêt que d’e^tre des struct capables d’émettre du String. Et dans ce cas, passer par du Javascript … n’est pas idiot. Parce que le travail énorme réalisé dans le monde du javascript ne se contente plus du client. Et que node.js reste une assez piètre idée, assez peu scalable. Du coup, joindre le meilleure du Java (le modèle, les capacités de traitement d’entreprise) au meilleur du javascript (tous ces outils de templating conçus par et pour le web) est vraiment chouette.

D’ailleurs, ça me donne des idées à propos de ractive/requirejs/Wisdom (mon trio de choc). Des idées qui n’attendent plus que deux choses

  1. Facile : le fameux bout de code transformant un require() en chargement de ressources depuis le CLASSPATH (d’après ce que j’ai compris, Sébastien travaille dessus)
  2. Moins facile : passer un template HTML plutôt que Javascript. Parce que s’il est question de rendu isomorphe, j’aimerais autant que ce soit le même fichier qui soit rendu de la même façon (ou presque) côté client et côté serveur.

Ce soir, c’est service workers, mais sans moi

Hélas, je ne suis pas au chtijug ce soir, et c’est bien dommage, parce que les service workers, ça m’a l’air bien intéressant. J’essayerai de chopper la présentation d’Hubert demain …

Et pourquoi je n’y suis pas ? Parce que je ferai demain une démo d’une application développée avec Wisdom, JCR, requirejs, Ractivejs, jQuery et Bootstrap. Tout ça a l’air d’une hypitude révoltante, c’est vrai, mais en fait c’est beaucoup plus simple  manipuler que ce qu’on croit. Si je voulais faire un rapide bon/pas bon, je dirais (même si vous le savez déja)

Bons côtés

  • Grosse productivité du live-reload de Wisdom incluant évidement les modifications du Javascript, du HTML, et même du POM
  • RequireJS est toujours aussi pratique pour ajouter des librairies Javascript sans se poser la question de la page dans laquelle ce Javascript est inclus … ou pas.
  • RactiveJS permet vraiment de faire facilement des interfaces modernes (surtout quand les templates Mustache sont chargés séparément via RequireJS).

Mauvais côtés

  • L’implémentation de wisdom-JCR interdit le live-reload. Et même si je suis en contact avec les développeurs de cette extension, c’est vraiment moche.
  • Dans le même ordre idée, avec wisdom, il ne fut jamais mettre un objet Java en cache, parce que quand on le charge après un reload, ce n’est plus le même objet Class, et du coup ça fait tout planter.
  • J’ai eu besoin de générer des images à partir de ppt/pttx. Eh bien curieusement, il n’y a aucune librairie qui ait vraiment le niveau pour faire ça de façon professionnelle.

Les mauvais côtés ont quand même bien failli tuer ce projet. Heureusement, ils ne l’ont pas encore tué … On verra demain soir.

Uploader un fichier en ajax sur un serveur Wisdom

Je pose ça là pour bien être sûr que j’ai bien tout essayé.

Donc, j’ai un scénario assez basique : dans une popup, écrite avec du Ractivejs/Bootstrap, j’ai un formulaire avec lequel je veux pouvoir uploader un fichier sur mon serveur écrit en Wisdom. Facile, non ?

Sauf que pour l’instant, ça ne marche pas.

Tout le code est dans ce gist (que WordPress ne semble vouloir inclure via ses smartcodes)

Le formulaire HTML semble correct. Et le javascript a l’air tout aussi normal.

En bonus, quand je passe en mode debug, j’arrive bien dans la bonne méthode de Wisdom.

Du coup, je jette un oeil à l’onglet network de Chrome, qui me donne ces infos

2015-05-24 10_41_46-p

Et là, si je ne me trompe pas, ça semble vouloir dire (en particulier, par exemple, Content-Length:44) que le fichier que je veux envoyer n’est pas là.

OK, donc c’est un problème côté client …

Et en fait, c’est une sale histoire entre jQuery et FormData. Ca me soulage : j’ai eu peur que Wisdom soit de la partie. Il me reste maintenant à corriger ce problème de Javascript … Qui se corrige en remplissant le Formdata avec le contenu de fileInputChooser.

Comme ça :

var file = $('#fileInputChooser')[0]
var formData = new FormData();
// Seems like auto-loading a FormData from a form do not work that well ... crap !
formData.append("fileInputChooser", file.files[0])

Ionic framework ?

Eh mais la semaine dernière, il y avait …

Et je n’en ai pas encore parlé ? C’est MOCHE.

Donc, ionic framework …

pour lequel Loïc fournit les slides :

Comme ça, je n’aurais pas à vous résumer le truc, mais juste à donner mon avis.

Ionic est donc une surcouche d’Apache Cordova pour y faciliter l’intégration d’AngluarJS et d’autres trucs. Ca permet de faire facilement des applis hybrides pour mobiles.

Les applis hybrides étant, pour ceux qui ne le sauraient pas, des applications web packagées pour ressembler aux applications système.

Au passage, un petit tacle à ceux qui croient que c’est moche : les jeux de chez Wargaming utilisent ce type d’application pour les garages de World of Tank/Warplanes/Battleships. Et pourtant, ça ressemble assez peu à un site web, il me semble. Donc dire que l’hybride est forcément une mauvaise solution me paraît un peu abusif.

Bref. On retrouve donc avec Ionic la possibilité de construire une appli mobile en web. Et, malheureusement, avec Angular. je dis malheureusement, parce que franchement, angular me sort autant par les yeux que JSF, et c’est pas peu dire.

Cela dit, la présentation était sympa.

J’ai même été particulièrement bluffé par l’intégration de Firebase. Je savais que cette base de données « as a service » existait. Mais je ne savais pas que c’était aussi chouette. Tellement que ça a éclipsé dans mon esprit toutes les idées du genre « mais pourquoi ne pas remplacer angular par Ractive ? »

Donc, une présentation réussie, mais pas pour son sujet principal.

Après deux mois de Javascript, on se sent comment ?

La question peut paraître … curieuse. Elle n’en demeure pas moins valide : quand on est comme moi un développeur Java un peu expérimenté, et qu’on passe d’un coup à ce langage aussi ubiquitaire que malaimé, qu’est-ce qui surprend ? Qu’est-ce qui étonne ? Qu’est-ce qui déçoit ?

J’ai vu des choses …

Avant d’aller plus loin, une petite mise au point. Je ne vais pas vous parler du dernier projet à la mode de lad ernière startup qui démarre. Non. J’ai fait du Javascript ces deux derniers mois pour la même raison qui m’avait forcé à faire du Flex pendant trois ans en pointillés sur le même projet : si vous voulez faire une extension pour indesign CC 2014, vous n’avez pas vraiment le choix, vous devez faire du HTML+Javascript. Alors du coup, je ne vais pas vous parler de Javascript qui communique avec son serveur via HTTP, mais de Javascript qui communique avec une extension Java/C++ via le système de communication créé par Adobe. Et, il faut le dire, Adobe fait des choix techniques … surprenants (j’y reviendrais).

En dehors de ces contraintes techniques spécifiques, l’application sur laquelle j’ai bossé n’a pas vraiment de spécificités. Enfin, pas trop 🙂

Alors, grunt, bower, npm ?

hrm hrm …

Je vais essayer d’expliquer ça de façon claire, même si ça va choquer.

Le projet pour lequel on fait cette interface est un projet multi-module de taille « moyenne » : 32 modules différents, compilant et générant tout un tas d’artefacts. Est-ce que j’allais introduire dans ce gros paquet de modules, et dans mon Jenkins, un autre outil, ou plutôt ensemble d’outils ? Non. Je voulais (peut-être de façon dogmatique) que cette interface soit packagée par maven.

Tester du JS dans maven, c’est possible ?

A la lumière de mes expériences avec Wisdom, je me suis dit que j’allais jeter un oeil à frontend-maven-plugin histoire de profiter de ses fonctionnalités (en particulier les tests). Mais, curieusement, je n’ai pas réussi à lui faire faire quoi que ce soit. Alors j’ai arrêté de faire le mariole, et j’ai dit à l’un de mes collègues de faire un système de test Javascript à base de Fluentlenium (qui est devenu pour une raison que j’ignore du Selenium pur et dur) et de JunitParams.

Autrement dit, pour chaque test Javascript, on crée un fichier HTML le chargeant via requirejs (j’y reviendrai) et on récupère grâce à Selenium le résultat du test via un peu de Javascript. Ca pique un peu les yeux la première fois, mais ça marche en fait très bien (même si tester du code asynchrone avec Jasmine est un peu compliqué).

Et les dépendances ?

Bon, évidement, comme notre projet n’utilise pas HTTP, nos dépendances Javascript (pour lesquelles Webjars rempalce très avantageusement NPM) nécessitent un peu de travail, essentiellement pour faire une translation de chemin qui les rende facilement utilisables.

Je m’explique.

Notre projet a (par exemple) ces dépendances :

		
	<dependency>
            <groupId>org.webjars</groupId>
            <artifactId>requirejs</artifactId>
            <version>2.1.14-3</version>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>requirejs-text</artifactId>
            <version>2.0.10</version>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>log4javascript</artifactId>
            <version>1.4.9</version>
        </dependency>
		

Comment je fais pour utiliser log4javascript sans m’emmerder à mettre son numéro de version partout ?

Parce que, par exemple, avec Wisdom (désolé de prendre cet exemple de façon systématique, mais son utilisation m’a appris quelques trucs vraiment chouettes), je n’ai pas besoin de mettre le numéro de version grâce au WebJarController.

Eh bien c’est … assez compliqué, et ça se fait en plusieurs étapes

  1. On a un script groovy (encore merci à gmaven) qui nous permet de créer pour les dépendances Javascript des propriétés maven. Les artefacts mentionnés me donnent donc les propriétés org.webjars:requirejs:javascript:require, org.webjars:requirejs-text:javascript:text et org.webjars:log4javascript:javascript:log4javascript qui deviennent faciles à inclure dans un <script src="${org.webjars:log4javascript:javascript:log4javascript}"></script>
  2. Le même script maven crée également une grosse variable ${requirejs.dependencies.compile.paths} qui sera bien utile pour générer le shim de requirejs.
  3. Et tous nos artefacts javascript sont dézippés grâce à amven-assembly-plugin pour générer l’application.

Alors évidement, toutes ces technologies sont infiniment moins hypes que les build tools Javascript, mais elles nous permettent d’intégrer proprement des dépendances Javascripts dans notre build et ça, ça fait plaisir.

Et requirejs, c’est vraiment bien ?

Vous allez rire (ou pas), mais pour l’instant, deux choses ont été embêtantes (mais résolues)

  1. Si vous chargez tous vos scripts avec le protocole file://, vous serez limités par la longueur maximale des chemins de Windows. Et si vous avez des gros chemins, par exemple pour des classes Java dans des packages profonds pour lesquelles vous générez des stubs Javascript à l’aide de flexmojos (essentiellement parce que GraniteDS intègre un super générateur pour les entités et les services – et ne me demandez pas comment je transforme mes fichiers .as en .js), eh bien vous allez pouvoir vous amuser à écrire un algorithme de translation de chemin et un plugin amven (ou un script gmaven) pour copier les bons fichiers aux bons endroits au bon moment (parce que amven-assembly-plugin est clairement dépassé, là).
  2. Et si vous avez des dépendances en scope compile et d’autres en scope test, ça ne posera pas vraiment de problème à requirejs, mis à part bien sûr qu’il faudra distinguer le data-main de l’un et de l’autre.

Mais dans l’ensemble, require me réconcilie vraiment avec le côté « packageless » de Javascript. Je n’ai pas besoin de faire ces fameuses fonctions anonymes auto-appelées. Je déclare chacun de mes fichiers presque comme je le ferais en Java, et tout (ou presque) est explicite. Le fait de travailler dans un environnement contrôllé donne un sentiment de sécurité asssez plaisant, et des fichiers déclarés selon une syntaxe vraiment agréable.

Et Ractive, c’est pas du flan ?

Ce qui est assez marrant, c’est que plus je m’en sers, moins je comprends les mecs qui font de l’angular (oui, ça sonne comme du bashing, mais c’est plutôt de l’incompréhension).

Il nous a été assez facile d’écrire des composants pas forcément triviaux, et à chaque fois qu’on se dit que Ractive pose un problème, il s’agit en fait d’un problème entre la chaise et le clavier (une erreur ID10T comme dirait mon collègue).

Et le fait de ne pas s’embarasser d’une gestion du modèle nous a permis d’utiliser ce fameux protocole de communication Adobe sans « trop » de problèmes.

Ah bon, alors vous faites pas de JSON ?

J’ai dit protocole, je n’ai pas dit format d’échange.

En fait, on utilise du JSON, mais sans passer par la librairie JSON fournie par Adobe (et je vous conseille de faire de même parce que cette librairie est buggée).

En revanche, échanger du JSON entre du Java et du javascript pose une question sérieuse : on part d’un monde typé, dans lequel chaque objet peut avoir des méthodes associées, méthodes pour lesquelles on aimerait bien disposer d’équivalents en Javascript. Par exemple, l’un de nos objets doit s’afficher en utiliser le resourceBundle fourni, on a donc envie de mettre la méthode dans le fichier Javascript généré par Flexmojos (pas de panique, Flexmojos en génère en fait deux : un qui sera réécrit à chaque build pour contenir les champs définis par le Java, et un autre généré une seule fois, dans lequel on peut ajouter notre code).

Mais comment fait-on pour que le JSON reçu du Java s’interprète non pas sous forme de hash anonyme, mais grâce à notre classe ?

Eh bien là, c’est vraiment compliqué :

  1. On demande à Jackson d’envoyer les informations de type dans le flu JSON grâce à son système de déserialisation polymorphe (on a utilisé jsonMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_OBJECT))
  2. Du coup, côté Javascript, on récupère des hashes qui associent à une classe le hash correspondant à l’objet, et là, c’est l’enfer : on a dû écrire un système qui « unmarshalle » ces hashes anonymes pour retourner des instances des classes Javascript correspondant aux aux classes Java. Et comme ça passe par require, il faut faire ce truc qui fait toujours peur : du code récursif asynchrone. Heureusement que Deferred est là, parce qu’il me semble que de tout le code Javascript, c’est la partie la plus compliquée que j’ai eu à écrire. Un enfer, je vous dit
  3. Ah, et en bonus, il ne faut pas oublier le code inverse : celui qui va prendre des objets Javascript ou des hashes anonymes pour créer de beaux obejts Java à l’autre bout du fil … Pas gagné.

Tiens, d’ailleurs, c’est le moment idéal pour vous rappeler que, comme les maps javascript n’ont pas de clés non string, ça ne peut pas être le cas non plus pour le JSON. Alors comme vous ne voulez pas réécrire tout votre code serveur pour votre nouveau client moderne, eh bien vous aller devoir vous taper la (dé)sérialisation des maps sous forme de tableaux de tableaux … Bon courage 😉

Autrement dit, comme d’habitude, la couche de communication va vous plonger dans un enfer sans nom, et surtout sans aucune raison valable.

Oui mais alors, le fait que ce soit pas compilé, qu’il n’y ait pas vraiment d’objets, c’est galère ?

Pour être honnête, oui.

Et pour être encore plus honnête, c’est pas trop grave.

Parce qu’en fait, il s’agit vraiment d’une interface HTML/Javascript : la partie complexe de l’application est bien au chaud, dans du code Java qui est correctement testé, qui a été écrit de façon à être raisonnablement robuste et qui est surtout déja utilisé en prod, donc qui a passé l’épreuve du feu.

Du coup, même si on galère parfois sur des histoires de types, ou de paramètres manquants/mal typés que Javascript ne voit pas parce que ça n’est pas son problème, ça n’est pas vraiment dramatique.

Et donc tu referais sans hésiter la même chose en plus gros ?

A dire vrai, mon Wiko a une version portable de Firefox qui fait fonctionner Ractive sans problème (comme Chrome, d’ailleurs). Alors du coup, demain, si je dois développer une application web, je peux vous assurer que le serveur se cantonnera à envoyer du JSON à mon client require/Ractive qui me fera, lui, une chouette interface.

Au passage, le bonus caché de Ractive, c’est que la philosophie est vraiment très proche de celle des web components, ce qui est loin d’être avantage mineur.

Eventuellement, j’ajouterais un coup de Facebook Flow pour valider mon code, et peut-être aussi que j’utiliserais plus frontend-maven-plugin pour minifier et toutes ces sortes de choses, mais dans l’ensemble, je comprend mieux ces histoires de microservices : si le client peut s’occuper d’aggréger et de présenter les données, pourquoi s’embêter à utiliser toute la pile JavaEE là où Wisdom suffit largement ?