Retour sur la réunion de travail GWT 2015 à Google

Ces derniers jours se déroulait à Google, Mountain View, le meetup annuel de l'équipe GWT. Une occasion pour tous les acteurs et contributeurs importants de se réunir et de faire le point sur l'état du framework, et surtout sur son futur.

Vous lisez un résumé de ce rendez-vous. Vous y apprendrez tous les secrets et tout ce qui se trame pour la version 3.0.

La plus grosse nouvelle pour la plupart d'entre vous va sûrement être la disparition des Widgets. Apprenez-en plus ici, et préparez votre futur !

Après lecture, vous saurez comment faire évoluer votre application GWT pour vous préparer aux nombreux changements (cassants) qui vont arriver en version 3.0 !

Pour réagir au contenu de cet article, un espace de dialogue vous est proposé sur le forum 13 commentaires Donner une note à l'article (5).

Article lu   fois.

L'auteur

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. GWT 2.8 et ensuite (présenté par Ray et Goktug Gokdogan)


Cliquez pour lire la vidéo


I-A. GWT 2.8, où en est-on ?

Voici le périmètre de la version 2.8 :

  • Java 8, toutes fonctionnalités implémentées ;
  • JsInterop ;
  • GSS ;
  • System.getProperty() : importer statiquement des valeurs passées au compilateur à la compilation ;
  • Performances et bogues fixes (type tightener par exemple).

Aujourd'hui, on est à 80 %/90 % de réalisation de l'objectif. Mais il y a encore des bogues avec les lambdas et les nouvelles reference methods de Java 8.

Au niveau de l'émulation, les packages java.util.function/java.util.stream ne seront pas émulés et l'équipe de GWT espère que la communauté prendra en charge cette partie.

I-A-1. JsInterop

Il y a eu des changements dans la spécification, qui est d'ailleurs toujours en mouvement. Mais le tout est dans un état de finalisation.

I-B. Et après ?

GWT a dix ans cette année. Le contexte a complètement changé depuis sa création. Il y a maintenant de nombreux frameworks UI de qualité comme React, Angular, Amber, Typescript, et tant d'autres outils puissants. Les mobiles aussi ont émergé. En fait, il faut trouver un moyen de faire levier sur tous les outils JavaScript qui existent aujourd'hui, et qui d'ailleurs n'existaient pas à l'époque.

I-B-1. Qu'est-ce que GWT ? Il fait tant de choses !

GWT est en fait tant de choses. C'est :

  • un transpileur ;
  • un optimiseur de code JavaScript ;
  • un processeur d'annotation ;
  • un système de build ;
  • un environnement runtime ;
  • une bibliothèque UI.

En fait, GWT supporte une complexité trop importante, surtout si l'on considère les outils standards qui existent par ailleurs et qui pourraient prendre le relais. Par exemple APT peut prendre le relais sur les générateurs. Pour les systèmes de build, il y a Maven, Gradle, Bazel… Pour les permutations, il y a le nouveau System.getProperty().

Il faut également adapter la sortie du compilateur GWT aux futurs modules ES6. Et faire levier sur le compilateur Closure compiler. En faisant la comparaison, on s'est rendu compte que si on désactivait les optimisations faites par gwt, Closure produisait des fichiers js de taille équivalente. Il est donc peu risqué de désactiver les optimisations GWT et laisser le travail à Closure.

Par ailleurs, il faudra aussi faire levier sur les API des navigateurs (à travers elemental, jsinterop et definitely typed).

I-C. Directions futures

La vision directive est que les mondes JavaScript et Java doivent fonctionner naturellement ensemble.

De plus, le compilateur doit être rapide, et conceptuellement plus simple pour faciliter sa maintenance et son évolution.

I-D. Ce qui va casser avec GWT 3.0

  • Les Widget seront complètement abandonnés (elemental, JsInterop ou autres systèmes de widgets).
  • Gwt-rpc aura également disparu en version 3.0. Il faudra plutôt utiliser l'Ajax pur et JSON.
  • JSO et JSNI vont être abandonnés.
  • Ne plus faire de générateurs, utiliser APT, ou System.getProperty() à la place du deferred binding.
  • GWT.create, c'est fini !
  • Finies aussi les permutations « user-agent ». Il faudra utiliser les properties systeme « user-agent » fournies par les paramètres de compilation. La valeur sera toujours résolue à la compilation et donc optimisée.

I-E. Et que va-t-il rester ?

  • Les fondamentaux :

    • l'émulation de la BCL Java ;
    • JsInterop ;
    • Elemental ou équivalent.
  • Utilisation accrue de bibliothèques tierces :

    • Singular ;
    • Polymer ;
    • React ;
    • Angular.
  • APT à la place de la génération de code GWT.
  • Utilisation de System.getProperty().

I-F. Pourquoi tout cela ?

Les gens se plaignent de la lenteur de la compilation. John Stalcup a travaillé pour améliorer les performances. Le SDM transcrit en JS avec un nommage stable, sans optimisation. Et il recompile seulement ce qui a changé.

Mais comparé à un compilateur C ou Java, le compilateur GWT est tellement compliqué. Ainsi, rentrer dans le code peut prendre des années. Même pour Ray, parfois corriger un petit bogue peut prendre beaucoup de temps.

Et le fait est qu'il serait intéressant de pouvoir profiter des frameworks modernes et populaires comme React, Singular, Angular…

De plus, GWT a été conçu pour créer des applications monolithiques. Avec GWT 3.0, on aura une compilation plus modulaire, avec des mécanismes similaires aux modules ES6, ou aux class loaders de Java.

Donc GWT va s'aligner avec la façon dont les applications JS fonctionnent (Async modules par exemple). Et du coup le compilateur va devenir beaucoup plus simple, donc plus réactif, plus performant et plus facile à maintenir. Très bonne nouvelle.

I-G. Le système de Widget

Pourquoi pas le porter en JsInterop, ça serait faisable, mais plutôt pour maintenir des applis. Ça ne serait pas du long terme.

En gros, simplement maintenir GWT tel qu'il est serait voué à l'échec. Il faut un changement de cap ! C'est un peu radical, mais la médecine est nécessaire.

II. La prochaine génération de compilateurs Java vers JavaScript (présenté par John Stalcup)


Cliquez pour lire la vidéo


Afin de dérisquer la vision évoquée précédemment, un prototype de nouveau compilateur a été développé. C'est un simple transpileur Java 8 vers JavaScript. Il ne fait aucune optimisation (ce sera le rôle de Closure compiler qui sera exécuté en fin de chaine). Aucun mécanisme de génération ni d'injection de dépendances. Ceci sera fait par le build système, et aussi par APT.

Les données en entrée sont toujours les fichiers source Java. GWT.create() sera inutile. Ce compilateur est entièrement focalisé sur la productivité du développeur.

La priorité est de pouvoir itérer rapidement. Inbox et Google Docs sont des gros clients. Les cas d'utilisation de GWT seront toujours les deux suivants :

  • pouvoir réutiliser du code logique métier Java dans une application client ;
  • pour ceux qui aiment simplement Java et veulent développer des applications web dans ce langage.

II-A. Expérience IDE

L'expérience IDE devrait être conforme à une utilisation classique en Java. Par exemple, en Java les fichiers .class sont générés à la volée. Ce devrait être identique pour les fichiers .js.

Donc cela sera sûrement plus simple pour l'utilisateur. Et aussi pour le développeur du transpileur (plus besoin d'un mode Super Dev Mode…).

II-B. Faire levier sur l'écosystème JavaScript

Avec Closure, on aura une très bonne optimisation. Il y a d'ailleurs dans Closure un mécanisme de permutations assez similaire à celui de GWT. Closure par défaut produit une seule permutation, mais il est possible de spécifier certaines propriétés qui doivent générer des fichiers JS spécifiques à la valeur de la propriété au moment de la compilation.

Le compilateur GWT générera du JavaScript ES6 très lisible. Les champs des classes seront directement déclarés dans les constructeurs JavaScript, de façon à laisser les VM JavaScript optimiser le code JavaScript de la meilleure façon possible.

II-C. ES6 et son système de module

Ce système est assez similaire au class loading de Java.

  • le name mangling doit rester pour supporter la sémantique Java (polymorphisme, méthodes virtuelles, constructeurs multiples…)
  • les classe literals n'existent pas en JavaScript.

Des exemples de codes JavaScript générés avec ce nouveau compilateur sont montrés, et il est vrai que le JavaScript est tout à fait lisible et compréhensible.

II-D. Architecture

Ces trois derniers mois ont été consacrés à prototyper ce nouveau compilateur. Le futur est donc déjà en marche !

Toutes les options ont été envisagées pour réaliser ce nouveau compilateur (écriture from scratch, utiliser le code de J2Objc, faire évoluer le compilateur actuel, utiliser d'autres compilateurs Java->JS qui fonctionnent sur le byte code). La décision a été de réécrire le tout.

Les solutions utilisant le bytecode Java comme entrée ne permettent pas à priori d'obtenir les meilleures performances, même si elles permettent d'ouvrir GWT aux autres langages s'exécutant dans la JVM (Scala, Groovy…).

II-D-1. Compilation

Pour compiler le Java, pourraient être utilisés JDT ou Javac. Ou bien on pourrait écrire un compilateur de zéro, mais trop long.

Donc l'architecture serait plutôt :

  • JDT comme processeur et générateur d'AST ;
  • transformation en AST GWT ;
  • transpilation immédiate en JavaScript.

C'est tout !

Comme vous le constatez, l'architecture est réduite à son strict minimum. Ce qui pour moi montre que l'équipe GWT a su extraire l'essence de GWT et qu'elle a su tirer les leçons du passé. Tout ceci montre que l'avenir de GWT est entre de bonnes mains.

II-D-2. Mode de génération des fichiers JavaScript

Les choix ici sont critiques quant à la qualité des fichiers JavaScript générés. Heureusement, l'équipe dispose d'ores et déjà de benchmarks qui permettront de bien évaluer les décisions architecturales prises.

II-D-3. À faire autour du nouveau compilateur

  • Rédaction de l'ensemble des sémantiques Java, de façon à implémenter rapidement quelque chose qui implémente la sémantique Java.
  • Un sous-ensemble de la JRE doit être émulé. On utilisera sûrement une version modifiée de la couche d'émulation actuelle.
  • IO et Thread seront toujours proscrits. Pour la réflexion, la décision n'est toujours pas prise. Peut-être un sous-ensemble de l'API de réflexion ? Le sujet reste ouvert, mais ce qui est sûr c'est que ce sujet a un impact très important sur les performances.
  • Une API DOM minimale.
  • JsInterop. Une bonne partie de la logique de JsInterop existe déjà dans Closure et pourrait donc lui être déléguée.
  • Intégration avec Bazel.

II-D-4. Performances

En termes de performances, voici les objectifs fixés :

  • taille des fichiers générés. En générant du code JavaScript compréhensible par Closure, la taille des fichiers générés est estimée à 25 % en dessous de ce qui est généré actuellement avec GWT ;
  • vitesse d'exécution. En fait au lieu d'optimiser le JavaScript, le mieux est d'éviter de perturber les VM JavaScript (ce qui est le cas avec les optimisations faites par le GWT actuel). La politique d'optimisation GWT change fait donc un virage à 180° !;
  • rapidité du transpileur. Cela doit être comparable à la compilation Java à la volée dans Eclipse, c'est-à-dire imperceptible.

III. Préparer vos applications à GWT 3.0 (présenté par Daniel Kurka)


Cliquez pour lire la vidéo


Comment programmer des applications GWT aujourd'hui de façon à ce qu'elles soient encore compatibles avec GWT 3.0 ?

Les générateurs, permutations et JSNI vont être abandonnés.

GWT fait trop de choses !

  • build system ;
  • optimizing compiler ;
  • bibliothèques intégrées (GSS…).

GWT a un énorme écosystème. Mais le contexte dans lequel GWT est né n'est plus valable. GWT est populaire pour ses performances, mais est détesté pour sa lenteur de compilation.

Si l'on réfléchit aux permutations, ce n'est pas vraiment un job pour le compilateur.

III-A. Le Rebinding

III-A-1. Replace-with

Aujourd'hui on utilise <replace-with>. Mais ceci va complètement disparaitre. À la place il faudra écrire (par exemple) :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
private static HistoryImpl impl = createImpl();

private static HistoryImpl createImpl()
{
    String userAgent = System.getProperty("user.agent");
    return "ie8".equals(prop) ?
        new HistoryImplIE8() :
        new HistoryImpl();
}

Ceci est tout à fait équivalent ! Et cela permet de déléguer la problématique des permutations au build system.

Notez que l'implémentation de System.getProperty() sera disponible en GWT 2.8, donc les applications auront la possibilité de se préparer en avance de phase au passage à la version 3.0 !

Ce nouveau paradigme aura l'avantage de vous permettre de grouper vos permutations à votre guise.

III-A-2. Génération de code

Les générateurs posent problème :

  • « Donne-moi toutes les classes qui implémentent l'interface X » est le genre de question que l'on peut poser au sein d'un générateur GWT. Mais ceci pose trop de problèmes pour écrire un compilateur incrémental.

APT qui est un standard Java propose pratiquement les mêmes fonctionnalités. Certes l'API d'APT n'est pas la panacée, mais certains projets peuvent aider dans ce sens : google auto, dagger, dagger 2, immutables, hexa.binding.

Quelques problèmes néanmoins avec APT :

  • l'API n'est pas terrible (c'est le moins que l'on puisse dire, et de ma propre expérience je confirme !) ;
  • si le générateur APT utilise une ressource, il n'est pas déclenché si cette ressource est modifiée, seulement quand un fichier Java est touché. Solutions possibles : avec Bazel ceci peut être pris en charge par le build system. Avec Maven, ceci prendrait quelque chose comme 10 secondes par itération : insupportable. Gradle : 3 secondes, toujours mauvais. Une solution (un serveur de dépendance) pourrait être que le générateur APT émette un fichier dans lequel il décrit tous les fichiers ressources utilisées, puis que le build system consomme ces fichiers et s'en serve pour déclencher le processeur d'annotation au bon moment.

Pour l'instant, voici les générateurs internes à GWT qui pourraient fonctionner en étant portés pour APT :

  • GSS et ClientBundle ;
  • I18N ;
  • UiBinder ;
  • SafeHtmlTemplates ;
  • PlaceHistoryMapperGenerator.

Mais un générateur pose de gros problèmes : GWT RPC. Il faudrait avoir plus d'informations dans les interfaces de service pour que le générateur puisse fonctionner en mode « APT » avec les bonnes informations, sans avoir à connaitre l'ensemble de la base de code de l'application (ce qui empêche toute sorte de compilation incrémentale efficace).

GSS et I18N seront sûrement portés vers APT.

III-A-2-a. I18N

Celui-ci aussi sera porté. Il consommerait toujours des fichiers de property, mais générerait plusieurs fichiers Java en une seule fois. Puis on utiliserait System.getProperty() pour sélectionner l'implémentation, ce qui permettra d'éliminer les implémentations non nécessaires à la compilation.

L'ensemble générera une factory à la place d'avoir à être utilisé avec GWT.create().

Une interface I18N ressemblera probablement à ceci (assez proche de ce que l'on a aujourd'hui) :

 
Sélectionnez
1.
2.
3.
4.
5.
@Translate({"de", "fr", ...})
public interface MyTranslations // plus d'interface de marquage
{
    String hello();
}

Pour l'utiliser, la génération APT fournira une factory que l'on pourra appeler ainsi :

 
Sélectionnez
1.
MyTranslations instance = MyTranslations_Factory.create();

Comme vous le voyez, la migration ne sera pas traumatisante !

III-A-2-b. GWT RPC

Cet outil a eu beaucoup de succès, car très transparent, presque « magique ». Mais il ne peut pas compiler efficacement, car il a besoin de connaitre l'ensemble des classes de l'application.

GWT RPC sera donc abandonné. Sans doute en faveur de Protobuffer, ou Rest. Mais le remplaçant n'est pas encore choisi !

III-A-2-c. Accès DOM

Si l'on regarde de près, les classes de gwt-user utilisent fortement JSO et JSNI, qui vont être abandonnés. Comme JSO et JSNI ne seront plus disponibles en 3.0, gwt-user sera complètement inutilisable !

Il faudra donc préférer les frameworks JavaScript à intégrer avec JsInterop :

  • Polymer ;
  • React ;
  • Angular ;
  • Singular ;
  • Tardigrade…

III-A-3. Singular, état

Le cœur est stable (on peut écrire des directives), le Singular expression language est implémenté, mais la sécurité doit être auditée.

IV. Conclusion

GWT est là depuis dix ans et a pris les bonnes décisions. Mais il faut maintenant envisager les dix années suivantes afin que GWT apporte toujours une valeur importante. Cette refonte apporte des changements majeurs et cassants pour la maintenance de vos applications.

En fin de compte, intégrer des Web Components se fera très facilement, avec une cuiller à pot. La migration de votre application vers la version 3.0 sera une tâche parfois ardue, mais nécessaire quand on considère toutes les innovations dont va bénéficier la nouvelle mouture de GWT. Il est impératif de préparer dès maintenant votre application, de façon à assurer votre futur. Côté GWT, Google prend les choses en main.

Cet article a été publié avec l'aimable autorisation de la société LTE ConsultingLTE Consulting.

Nous tenons à remercier Claude Leloup pour sa relecture attentive de cet article et Mickaël Baron pour la mise au gabarit.

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Copyright © 2015 Arnaud Tournier. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.