Disclaimer : cet article date de fin 2011… Je viens de le sortir de la cave comme une bonne bouteille. Les lecteurs fidèles y retrouveront mes poncifs et cela fera un peu répétitif. Mais bon, comme un bon vin, il fallait le laisser vieillir.
La scène se passe il y a quelques mois. Il est 2h10 du matin.
Cela fait plusieurs heures que je clique et que je travaille dans ce logiciel Web pour un client, un truc de CRM/Wiki/Machin en java. C’est une application Web, écrite avec un framework Java, peu importe le nom. Il y a des formulaires à remplir. Je remarque que le développeur qui a fait cela s’est lâché sur l’utilisation de l’ajax. Il y a des listes déroulantes qui se remplissent via une requête Ajax.
J’imagine que le développeur a passé un certain temps à « ajaxiser » ces 3 pauvres listes déroulantes. La première permet de choisir son pays. Quel génie ce mec : il a ajaxisé la liste des pays, dès fois que l’Argentine disparaisse et qu’un autre pays soit ajouté, au moins on est tranquille. Il doit recharger du serveur cette liste de pays. Super mon champion.
Comme c’est de l’ajax, je me dis que je peux commencer à faire autre chose pendant que la PREMIERE liste essaye de dire que j’habite en FRANCE au serveur. Je tente la sélection de mon genre (Homme/Femme) toujours ajaxisé pour envoyer la sélection au serveur…. Baam cela plante la page… Je rigole. C’est de l’Ajax mais codé par un paysan.
Bon disons qu’ensuite j’arrive à remplir ce formulaire et à l’envoyer au serveur… toujours en Ajax… sans m’empêcher cependant de cliquer plusieurs fois…
Je regarde ce petit GIF animé qui tourne en haut à droite qui me signale qu’il faut attendre et ne surtout pas toucher à autre chose, même si tout est fait en Ajax. J’imagine différentes tortures et supplices pour celui qui a codé cela. J’essaye de deviner le nom du framework en regardant l’URL, mais comme souvent en Java, elle ne ressemble à rien.
Ah c’est bon, la deuxième liste déroulante s’est remplie. Je sélectionne le département. Et là une troisième liste repart vers le serveur, GIF animé pour dire « TOUCHE PAS C’EST DE L’ASYNCHRONE »… J’imagine la bouteille d’Ajax avec une paille dans le nez du développeur…
Il est 2h25, je suis fatigué….
Le GIF animé tourne, tourne, tourne…
Je m’endors.
Il est 3h du matin, j’ai piqué du nez. Ma fenêtre de navigateur n’a pas bougé. Je reprends la souris pour terminer mon boulot. Je clique sur un bouton et là… et là mon ami : une page d’erreur. Un petit texte rouge bien présenté, entouré d’un cadre rouge foncé, s’affiche sur la page. A croire que le développeur Web a mis tout son budget dans le CSS « error-box » avec la même énergie que ses exploits avec Ajax…
« Your session has expired«
Mais c’est quoi ce message ?
Je pensais que nous, développeurs Architectes Java, inventeurs de l’Inversion de Contrôle pour les masses, maître Jedi de la séparation des couches, super-kungfu master du mapping objet-relationnel, oui nous LES ARCHITECTES, je pensais que l’on avait compris qu’une application Web devait gérer la session.
Genre y’a que lorsque tu fais du Java que tu as ce genre de soucis. Va faire 5mn de Rails ou de Django et on en reparle.
Ah pardon… c’est vrai que c’est pas entreprise ou « un projet de la vraie vie ».
Bref un GIF animé et une session qui a expirée. J’imagine que le développeur a séparé en plusieurs couches son code, en mettant une tartine de JPA, une abstraction avec des entités, une tartine de service, un fine tranche de sécurité et un gros paquet de framework web pour empaqueter le tout… Oui mon gars, les couches c’est bien, mais il faut aussi un peu comprendre ce que l’on fait non ?
Le protocole HTTP est simple. 5 verbes de commandes. Il faut au moins comprendre GET et POST. Essayons de se dire que GET est destiné au chargement d’une donnée, et que POST est destiné à modifier une information sur le serveur. Un principe de base : une succession d’appel via GET est dit « idempotent » alors qu’une suite d’appels via POST ne l’est pas. De là, comprendre la notion de ressources, d’URI, d’adressage, bref du web quoi.
Gregor Hohpe, l’auteur du livre Enterprise Integration Pattern, l’explique simplement sur son blog :
“In the world of distributed systems, idempotency translates to the fact that an operation can be invoked repeatedly without changing the result.”
Ensuite, le protocole HTTP est stateless.
The Hypertext Transfer Protocol (HTTP) is an application-level protocol for distributed, collaborative, hypermedia information systems. It is a generic, stateless, protocol which can be used for many tasks beyond its use for hypertext, such as name servers and distributed object management systems, through extension of its request methods, error codes and headers [47]. A feature of HTTP is the typing and negotiation of data representation, allowing systems to be built independently of the data being transferred. (source)
La notion de session n’existe que grâce aux Cookies, à la ré-écriture d’URL ou lorsque vous postez des données dans des champs cachés. Tout le reste, ce n’est pas du Web. Lorsque vous avez un cookie technique JSESSION_ID qui se balade avec vous, et que l’état de ce que vous êtes entrain de faire dans l’application est stocké en mémoire, vous utilisez une application avec un état conversationnel du côté serveur. Je ne dis pas que c’est bien ou pas bien. Je dis que cela entraîne des problèmes qui n’existent pas lorsque vous faîtes vraiment du Web.
Lorsque nous utilisons des cookies signés pour stocker des identifiants de session, on imagine qu’il faut ensuite recharger de la base de données toutes les informations… C’est possible et cela fonctionne correctement, mais la base de données n’est pas faite pour cela. En règle génèrale on utilise alors un cache partagé avec ehcache, memcached ou Redis. C’est bien plus efficace que de laisser faire le framework Web à votre place.
Lorsque j’ai vu le message « Your F**ing sesson has expired », je me suis vraiment interrogé sur la motivation du développeur du framework qui a pondu cela. En quoi n’est-t-il pas capable de stocker un état et de le recharger lorsque je relance ma requête ?
En observant les URLs, nous avons le début d’une réponse (j’ai changé le nom du framework pour respecter son anonymat) :
http://www.monserveur.fr/?crocket:interface=:6:1:::
Qu’est-ce que c’est que cette URI ? Mais c’est de la merde comme dirait Jean-Pierre. Ce n’est pas du Web, c’est un produit industriel bourré de polyphospates que l’on pense utiliser pour faire des économies, mais qui ne vaut rien !
Bref dans un grand délire mégalowebmaniac j’ai lancé une phrase à 2 balles dont je ne mesure pas la portée mais que j’ai envie de proposer à toi, cher lecteur. Cette phrase, la voici :
Votre session n’a pas à expirer pour un problème technique.
Une session devrait expirer pour une raison métier mais pas pour des raisons techniques. Elle ne devrait pas expirer parce qu’un créateur de framework pense que c’est le seul moyen de libérer des ressources.
En poussant un peu, nous pourrions dire que le message « technique » signifiant que votre session a expiré ne devrait pas exister.
Du tout.
Lorsque vous rechargez la fenêtre de votre navigateur, et que l’état, la session ou la conversation est perdue, vous n’êtes pas entrain d’utiliser une application Web. La bonne nouvelle c’est qu’une grande majorité des frameworks Webs Java gèrent cela sans trop de soucis. La mauvaise nouvelle c’est que ce n’est pas l’approche recommandée ou documentée dans les tutoriaux.
Qu’est-ce qu’une application Web ?
Il s’agit d’une application hébergée sur un ou plusieurs serveurs, utilisée via un navigateur ou une API REST.
C’est une application qui passe ce test :
– fonctionne avec plusieurs onglets de navigateur
– propose des URI facilement bookmarkable, voire même qu’un utilisateur peut retenir
– utilise correctement GET et POST
– fonctionne de manière transparente avec un ou plusieurs serveurs sans problèmes de session
– n’utilise pas de GIF animé pour faire attendre l’utilisateur
– ne plante pas comme une merde lorsque l’utilisateur clique sur le bouton « Back » ou retour.
– ne plante pas lorsque je clique comme un bourin sur « Reload » une centaine de fois pour me défouler, surtout lorsque je vois « crocket » dans l’url du navigateur
– ne génère pas des pages webs de 700ko avec 3 pauvres tableaux ajaxisés.
La majorité des frameworks Webs permettent de suivre et de respecter ces principes.
Alors où stocker ces données de conversation ?

© kritiya – Fotolia.com
Il y a différentes solutions utilisées aujourd’hui dans le développement d’applications :
- mettre plus de mémoire et prétendre que ce problème n’arrive pas « sur les vrais projets de la vraie vie »
- stocker les id des objets primaires dans un cookie signé et recharger les entités de la base à chaque appel
- utiliser un cache partagé comme memcached, ehcache ou redis, stocker un jeton dans un cookie signé et charger les id des objets primaires dans un cache
- passer par la ré-écriture d’URL simple
Imaginez un seul instant ce principe : votre session « technique » ne doit pas expirer, jamais. Si quelque chose expire, cela doit être lié au métier. Mais pas à un problème technique ou à une décision prise par le framework.
Bref, j’ai terminé à 03h10.
0 no like
Sinon on peut aussi mettre des input type hidden un peu partout dans l’appli 😀
« http://www.monserveur.fr/?crocket:interface=:6:1::: » => Les « : » me font penser à du Wicket.. Rien de sûr, mais ce #&!@ de site du CFP Devoxx est en Wicket, et ya des f*cking « : » partout dans l’URL…
@Piwaï en même temps crocket ça me fait penser également à… de la nourriture pour chat ou chien 😉
Dans le framework Wicket, pour avoir des urls correspondants à vos specifs, il suffit d’employer le MountedMapper correspondant.
Wicket est un framework statefull, d’où l’usage de la session.
Concernant la Session, celel-ci n’est pas propre à un framework ni à un language.
http://en.wikipedia.org/wiki/Session_(computer_science)
Bon dev
François
@Francois,
+1000
des petits rappels ne font pas de mal de temps en temps.
Adrien
Il y a aussi un autre problème de design à la base.
En quoi la liste des pays devrait elle dépendre de l’utilisateur connecté ?
Plus généralement la liste des pays devrait être une ressource REST générique accessible par tous les users. Il n’y a donc pas besoin d’avoir une session active pour la récupérer…
Evidemment se pose le problème de sécuriser l’API Rest pour éviter les attaques DDOS mais c’est un autre sujet…