JSF, je t'aime, moi non plus !

jeu. 24 janvier 2013

Connaissez-vous JSF (Java Server Faces), cette fabuleuse technologie Java destinée à la création d'écran  ? Ce framework que votre direction technique va vanté car "les développeurs n'ont plus besoin de connaissances en javascript et/ou html !". Votre commercial ? Lui sera ravi car il affichera l'utilisation d'un standard Java. Et les développeurs ? Ils vont enfin pouvoir se concentrer sur les tâches intéressantes : coder les règles métiers ! Bref, JSF réunit les foules et permet à tous de travailler dans une unité parfaite !

Ah, que ce monde serait parfait ainsi !

Malheureusement, l'eco-système Java est loin d'être un univers de Bisounours... Tout n'est pas aussi rose ! Laissez moi vous présenter cette fabuleuse brique logicielle et déverser toutes la haine que j'ai apprit à avoir, cette année, sur ce sujet...

JSF en quelques mots

Commençons par replacer le contexte. JSF est une technologie faisant parti du Corpus Java / J2EE et fortement utilisée sur les projets Java récents. Nous sommes actuellement à la version 2 du produit, version que votre humble serviteur à expérimenté pour vous (bon, en réalité pour son travail).Il s'agit donc d'une technologie mûre et conçue par des experts, une référence en quelque sorte.

JSF est orienté composant : votre page web n'est donc plus vue comme un assemblage de balises html simples, mais comme un écran complet, avec des composants riches et dynamiques, une gestion d'évènements,... JSF se destine donc à être le Swing du Web (pas sûr que cette référence soit flatteuse toutefois). Ici, finit le "binding" manuel entre vos petits données Java et leurs correspondances coté écran. Comment cette approche riche se traduit-elle concrètement ?

D'un coté, vous aurez une page JSP utilisant non plus les tags standard, mais des tags spécifiques à JSF. Les composants et données vont ensuite être mappés à leurs correspondants coté Java. A chaque action utilisateur sur l'écran, le controlleur (objet lié à l'écran) est mis à jour. A chaque modification coté Java, l'écran est également rafraichit. Petite nuance toutefois  : le mapping est désynchronisé, il a lieu quand l'action "soumet" la page (comme l'envoi d'un formulaire, une requête Ajax,...).

Concrètement, à chaque fois que vous validez une page il va se dérouler les étapes suivantes :

  • Récupération de la page soumise par le client
  • Restauration des composants de la page dans leur état initial
  • Validations et conversions des nouvelles valeurs
  • Mise à jour des objets Java avec les nouvelles valeurs
  • Déclenchement des évènements
  • Déclenchement de l'action demandée par l'utilisateur
  • Déclenchement des évènements (s'il y en a des nouveaux suite au passage de l'action)
  • Réecriture de la page
  • Sauvegarde de l'état de la page
  • Envoi au client de la page mise à jour

Cette liste est uniquement un aperçu du cycle de vie. Elle illustre toutefois assez bien ce qu'il se passe réellement.

La Force de JSF

C'est bien beau tout cela, mais en quoi JSF est-il meilleur que la "vieille" JSP. Voilà ce qui m'a convaincu sur cette technologie :

  • Le binding est vraiment simple à utiliser et à mettre en place
  • Finit les multiples bidouilles effectuées uniquement dans le but de conserver l'état de la page ou de provoquer des évènements
  • Pour peu que l'on ajoute une librairie tierce de composants avancés (PrimeFaces, RichFaces), il est alors facile de créer des pages dynamiques sans une ligne de javascript (sans lignes codés par le développeur, la librairie fournissant les composants directement avec le javascript qui va bien).

Au final, dès que le coup de main est pris on crée les écrans très rapidement. On peut donc se concentrer uniquement sur la logique métier, ce qui n'est pas pour nous déplaire.

Et le coté obscur...

Si la productivité est aussi bonne, pourquoi j'ai utilisé dans l'introduction le mot "haine" ?

Commençons par le point fâcheux : les "bugs" ! Ah non, excusez-moi, on m'informe dans l'oreillette qu'il ne faut pas parler de bugs mais de "limitations techniques" !

JSF met à notre disposition un container permettant de stocker nos beans. Les objets ainsi sauvegardés ont un "Scope", une portée qui détermine quand ils sont crées et quand ils sont détruits. On retrouve les classiques "Session" et "Request", mais également le scope "Vue". Ce dernier indique que les valeurs sauvegardés seront conservés tant que l'utilisateur n'aura pas changé d'écran. Nous somme donc sur une sorte de mini-session ! Attrayant non ?

De mon coté, j'ai trouvé l'idée géniale, puis j'ai découvert à mon insu les limitations. Mesdames et Messieurs, sachez que si vous souhaitez capitaliser facilement grâce aux composants facelets, si vous utilisez des objets non serializable, ou si vous avez eu besoin d'utiliser un bête foreach dans votre maquette, votre joli scope Vue partira en morceau (et sans même daigner vous prévenir). A chaque validation de la page les beans seront donc recrées à neuf. Je vous laisse imaginer combien de temps ce genre de bug est capable de faire perdre avant que la solution ne soit trouvée ;) De mon coté, j'ai pesté quelques journées...

Ok, c'est tout ? Non malheureusement, j'ai rencontré d'autre soucis mais qui sont, je pense, imputable à RichFaces (dans sa version 4). Lesquels ? Vous avez un composant tout beau que vous décidez d'inclure ! Nickel ! Tout se passe bien, vous êtes content. Là votre client le voit, et il vous demande de l'intégrer aussi sur la page d'à coté ! Après tout, quand c'est beau à un endroit de l'appli, autant que ça soit beau partout... Vous faites donc l'opération mais là, c'est le drame... Votre joli composant est inactif : aucun css ne s'applique, aucun Js n'est chargé... Pourtant, RichFaces aurait du s'occuper de tout !  Après pas mal de prise de tête nous avons inclus manuellement les fichiers manquants...

Ok, mais encore ? Hop, on va rajouter une petite popup (il n'y a que ça de vrai !). Celle-ci est munie d'un beau bouton qui déclenche une action (normal). Vous testez, cliquez un coup sur le bouton, et... rien ! Vous cliquez à nouveau, et là, l'action se déclenche ! Et oui, seul le deuxième click semble fonctionner ! Ici encore, j'ai heureusement trouvé un contournement (lancer un reload de la popup lors de son "onShow", mais c'est une bidouille qui m'a prit du temps.

Je pourrais vous citer d'autres exemples... Au final, on a eu l'impression de perdre en bidouille le temps que l'on avait gagné en amont.

Une mémoire pour les gouverner tous...

Reste un dernier point problématique avec JSF : les performances et la taille de la mémoire. Regardez à nouveau le cycle de vie, vous avez vu tout ce qui est fait à chaque action ? Tout ces points, bien qu'optimisés, prennent du temps et des ressources. Avec 1 utilisateur, ça va, mais avec 100 000 ?

JSF effectue également une "sauvegarde de l'état",... Il faut de la mémoire pour stocker tout ça ! Et oui, JSF a un coup pour votre exploitation ! C'est un point à ne pas oublier... Surtout que l'architecture JSF nous incite à stocker encore, et encore, et encore, et toujours plus d'informations (c'est tellement facile).

Bref, si vous comptez avoir énormément d'utilisateurs et que vous voulez éviter un coût démesuré d'infrastructure, je ne peut que vous conseillez de choisir une autre technologie...

En conclusion...

Partant d'une bonne idée, JSF est toutefois très loin d'être parfait. Il ne s'agit pas de la solution ultime à tous vos problèmes. Pour une petite application simple et extrêmement standardisée, vous arriverez à une productivité sans équivalent. Pour une application complexe par contre, faites un autre choix... Play ? Spring MVC ? Autant de solutions très séduisante et bien plus légère.