mercredi 7 juillet 2010

Notifier une expiration de session utilisateur en Ajax

La problématique :

Dans la plupart des applications Intranet ou Extranet, le serveur gère un délai d’inactivité pour les sessions utilisateurs. Concrètement, cela veut dire que s’il se passe un certain délai (deux heures, par exemple) pendant lequel le serveur ne reçoit aucune requête HTTP de la part du client, le serveur prend l’initiative de détruire immédiatement et définitivement la session utilisateur. Cela veut dire qu’à partir de ce moment là, les données de l’utilisateur qui étaient préalablement stockées en session ont disparu. Ce mécanisme est important pour différentes raisons :
  • Il permet de libérer de la mémoire devenue inutilisée sur le serveur
  • C’est un élément des mécaniques de sécurité, indispensables dans les applications comme le webmail ou l’accès à des comptes bancaires.

Du point de vue de l’utilisateur, l’approche n’est pas la même. En fin de matinée, Jean-Paul se connecte à notre application pour traiter un document. Puis quelques minutes plus tard, il verrouille sont poste de travail et part déjeuner avec ses collègues. A son retour, café brûlant en main, il consulte ses mails, passe un coup de téléphone, puis reprend le traitement de son document. Il saisit ses données, clique sur le bouton de validation, confirme, et là… c’est le drame ! Sa session a expiré. Il doit se reconnecter, mais surtout, il doit recommencer le traitement de son document.
Alors comment faire pour satisfaire Jean-Paul sans désactiver les sécurités présentes sur le serveur d’application ?

Une solution simple et efficace :

Voici une solution extrêmement simple et facile à mettre en œuvre :
  1. Au chargement de la page HTML, déclencher un compte à rebours en Javascript sur le client.
  2. Lorsque le compte à rebours se termine, faire un appel Ajax pour vérifier si la session est effectivement terminée.
  3. Si la session a expiré, prendre l’action adéquate (i.e. rediriger l’utilisateur vers la page de connexion).

Le compte à rebours sur le client sera initialisé avec la durée du Timeout de session sur le serveur augmentée de quelques secondes par mesure de sécurité.

Mise en œuvre avec jQuery dans un environnement JSP :

Voici un exemple d’implémentation en jQuery et JSP. Ci-dessous, le code à intégrer dans les pages HTML.




A l’expiration du compte à rebours, un appel Ajax est déclenché vers la page checksession.jsp. Dans l’exemple donné ici, l’utilisateur est redirigé vers l’URL renvoyée par checksession.jsp. Voici le code de cette page :




L’idée est de tester la valeur d’un attribut de session connu que l’on sait non vide. S’il est vide, c’est que la session a expiré, et on renvoie dans la réponse HTTP la ressource vers laquelle rediriger l’utilisateur. Simple et efficace…

Améliorer le look and feel d’une application web

La deuxième moitié des années 2000 a été le théâtre de bouleversements majeurs dans nos navigateurs : démocratisation de l’Ajax, Web 2.0, réseaux sociaux ou collaboratifs, wikis… Aujourd’hui, il est fréquent que les applications web que nous utilisons dans notre vie privée – GMail, Yahoo!, Facebook, Picassa, Flickr, blogs – soient plus ergonomiques que celles que nous utilisons dans notre vie professionnelle. Si les utilisateurs finaux doivent s’en accommoder (ont-ils vraiment le choix ?), cette situation n’est pas satisfaisante lorsque l’on est éditeur de logiciels ou responsable applicatif au sein d’une grande organisation. Alors que faire ?

La méthodologie :
Pour un tel projet, qui ne comprendra finalement principalement que des modifications de style et d'ergonomie, inutile d'annoncer le lancement d'une v3 de l'application! Un cycle en V semble également peu adapté, pour de nombreuses raisons :
  • les phases amont au développement (architecture, spécifications, conception détaillée) sont souvent produites sous forme de documentation qui seront difficiles à valider par une MOA ou un département marketing,
  • certaines phases en aval du développement comme les tests unitaires seront difficiles à réaliser dans ce contexte,
  • risque d’effet-tunnel avec des délais difficiles à maîtriser
  • risque de surprise des clients (département marketing, MOA, utilisateurs finaux) en cas d’écart entre ce qui a été produit et ce qui est attendu.

Pour ce genre de démarche, il faut oublier la lourdeur du cycle en V et préférer une méthode permettant de faire des livraisons fréquentes, comme une méthode itérative ou une méthode agile de type SCRUM. Les livraisons sont facilitées par l’architecture même des applications web qui nécessitent seulement un déploiement sur un serveur et permettent :
  • A l’équipe de développement de montrer que le travail avance régulièrement
  • Aux clients de s’approprier le nouveau look de l’application sans être déroutés
  • Aux clients de faire des retours et de soumettre leurs idées pertinentes
Une livraison toutes les 4 à 6 semaines (en fonction de la durée du projet) semble un bon rythme. Il est intéressant, si c’est possible, de formaliser les livraisons en présentant les nouveaux éléments aux clients. A chaque livraison, l’équipe de développement fera en sorte de livrer des tronçons complets pour ne pas donner l’impression de travail inachevé. Elle introduira également les retours sur la version précédente dans la mesure de ce qui a été convenu.

La stratégie :
Si l’objectif est d’améliorer l’expérience utilisateur, et de livrer quelque chose de visible tous les mois, il faut être efficace. Dans ces conditions, pas question de remplacer le vieux framework MVC maison par un standard du marché : la valeur ajoutée utilisateur est proche de zéro.
Inutile non plus de tenter une migration vers le dernier framework de développement RIA, genre GWT ou Flex. Cela ne serait pas compatible avec la démarche définie ci-dessus… et les risques de régressions fonctionnelles sont énormes, surtout s’il existe du code métier dans les pages faisant le rendu HTML, ce qui est fréquent !

Une stratégie à la fois raisonnable et efficace est de transformer progressivement l’application en remplaçant certains éléments existants, ou bien en ajoutant de nouveaux éléments. Pour cela, il faut choisir une librairie Javascript suffisamment riche pour :
  • Proposer nativement des éléments graphiques comme des fenêtres modales, des datepickers, des accordéons, onglets, etc.
  • Manipuler dynamiquement les éléments du document au travers de sélecteurs
  • Mettre en place facilement des appels AJAX
  • Permettre la création de plugins (pour pouvoir en réutiliser !).

La bibliothèque jQuery est particulièrement adaptée pour ce type de réalisation, car elle a un excellent équilibre entre sa valeur ajoutée intrinsèque et son niveau d’intrusion lorsqu’elle est insérée dans une application existante. Il faut dire qu’avec seulement quelques fichiers .js et .css à inclure (si l’on adjoint jQuery UI), il est difficile de faire moins intrusif ! De plus la clarté de sa documentation et la quantité de blogs de développeurs s’y référant rendent sa mise en œuvre rapide.

La mise en œuvre :
Voici quelques idées de transformations simples qui ont un impact immédiat :
  • Remplacement d’anciens calendriers s’ouvrant dans une fenêtre popup (utilisation du composant datepicker de jQuery)
  • Utilisation de tables triables et paginées dès que le nombre d’éléments à afficher dépasse quelques dizaines. Utilisation de cookies pour enregistrer ordres les tris et les choix de pagination
  • Utilisation du drag and drop pour sélectionner quelques éléments parmi une liste
  • Création d’un espace dans lequel l’utilisateur peut personnaliser l’application : choix d’un thème, des options de l’application,
  • Ajout d’un composant affichant en temps réel la complexité du mot de passe utilisateur lorsqu’il est modifié
  • Suppression des fenêtres popups qui compliquent la navigation (utilisation du composant dialog de jQuery)
  • Utilisation d’appels AJAX lorsqu’il faut mettre à jour une très faible quantité d’informations sur une page. Dans ce cas, retourner soit des chaînes de caractères pour du texte, soit un objet JSON pour des tableaux ou des objets structurés.
  • Restructurer les pages trop denses soit en les découpant, soit en utilisant des composants comme les onglets ou les accordéons
  • Dans les formulaires, ramener les contrôles de format sur le client : taille maximale, formats numériques, monétaires, codes postaux, etc. Cela évitera des rechargements de pages en cas d’erreurs de saisie
  • Valider que la navigation au clavier est opérationnelle dans tous les formulaires de saisie,
  • Dans les formulaires encore, ajout d’aides à la saisie, comme le format attendu d’une date, d’un n° de téléphone, ou encore le nombre de caractères restant lors d’une saisie dans une textarea.
  • Lors d’une erreur de saisie dans un formulaire, indiquer clairement dans quel champ se situe l’erreur, et quelle est la nature de l’erreur. Mettre bien évidemment le focus sur ce champ.

Lors de la mise en œuvre, le responsable des développements devra garder en tête que ce sont les petits ruisseaux qui font les grands fleuves…

mardi 22 juin 2010

5 clés pour intégrer des composants existants à une application SaaS

Depuis plusieurs années maintenant, des éditeurs et des prestataires se lancent dans le SaaS pour compléter leurs gammes de services et de logiciels traditionnels. Cependant, pour réduire les coûts de développements et les délais de mise de sur le marché, la tentation est grande de réutiliser des composants existants en les intégrant au sein d’une plate-forme SaaS. Il peut s’agir de composants purement techniques (téléchargements, conversions d’images ou de documents bureautiques), de services métier à forte valeur ajoutée comme la LAD (lecture automatique de documents) ou encore de requêtes vers de services tiers.

Un schéma simple et efficace est de connecter à l’application SaaS des composants métiers ou techniques qui remplissent une ou plusieurs fonctions précises. Chacun de ces composants communique directement avec l’application principale par des files de messages ou des services web.
Lors de la mise en œuvre, il faut être particulièrement vigilent, car le monde du SaaS a des exigences très spécifiques. Voici un petit tour d’horizon des contraintes à connaître et des pièges à éviter :

Haute disponibilité :
L’objectif de disponibilité des applications SaaS est le 100%. Lors de l’intégration d’un composant existant à une architecture SaaS, il faudra donc définir une stratégie prenant en compte la gestion des pannes de ce composant, de ses montées de versions. De même si ce composant repose lui-même sur un composant tiers (i.e. une base de données), il faudra prendre en compte les indisponibilités (planifiées ou non) de ce sous-composant.
Dans tous les cas, l’application principale ne devra jamais se retrouvée bloquée.

Scalabilité :
La scalabilité peut être définie comme la capacité d’un système à étendre (ou réduire) facilement ses ressources à mesure que la charge augmente (ou diminue). Si une application SaaS est bien conçue, sa capacité de traitement évolue linéairement avec la quantité de processeurs/RAM qui lui est allouée.
Malheureusement, certaines applications ne sont pas capables de tirer correctement partie d’une architecture multiprocesseur. Dans ce cas, il faudra déployer l’application sur plusieurs machines (éventuellement virtuelles) et mettre en place un mécanisme de répartition de charge (load-balancing). Cela peut engendrer des coûts d’exploitation supplémentaires, ainsi que des délais de mise à disposition importants de ces nouvelles machines selon l’hébergeur.

Temps de réponse :
Dans le monde du web, l’utilisateur déteste attendre… et il a raison ! Quelques secondes, ou au plus quelques dizaines de secondes si une barre de progression est là pour le distraire. La maîtrise des temps de réponse est donc primordiale, pour gagner de nouveaux clients, mais surtout pour satisfaire et conserver ses clients actuels.
S’il y a des doutes sur la capacité d’un composant à s’exécuter dans un délai prévisible et raisonnable, il vaut mieux prendre ses précautions : on pourra lancer le service de manière asynchrone pour rendre la main immédiatement à l’utilisateur, puis dans un second temps le notifier du succès de l’opération.
On peut aussi déclencher au lancement du service un compte à rebours : si ce dernier se termine avant l’arrivé des résultats attendus, on pourra lui présenter des résultats partiels et éventuellement lui proposer de poursuivre la recherche pour obtenir de nouveaux résultats.

Exploitation :
Une fois que la plate-forme de production est installée chez l’hébergeur, pas question de se connecter tous les matins pour prendre la température des applications. Nos petits composants sont lâchés dans la nature, comme des skippers au milieu de l’océan. Il est donc primordial qu’ils soient capables de communiquer eux-mêmes en indiquant périodiquement leur état, en indiquant leurs défaillances dès qu’elles surviennent, ainsi qu’en prenant des mesures pertinentes dans leur environnement : espace disque, accès aux ressources externes, consommation de licences, etc. Les modes de communication peuvent être variés, voire même combinés : emails, alertes vers un outil de supervision de plates-formes (Patrol, $Universe), portail de supervision métier accessible en client léger, etc.

Documentation :
D’une manière générale, on documente pour éviter que les seules personnes capables de faire fonctionner un logiciel soient ceux qui l’ont développé ! Ceci prend tout son sens dans le monde du SaaS où il est fréquent que les équipes d’exploitation soient localisées dans des pays émergents et avec lesquelles la communication se fait obligatoirement en anglais. L’anglais entre non anglophones… quel bonheur !
Il est également important de garder à l’esprit que les exploitants n’ont aucune idée de ce que fait notre application. Les documents d’installation devront donc être le plus clair possible, et prévoir des procédures de vérification permettant à minima de s’assurer que l’application est bien opérationnelle à la fin de l’installation !


vendredi 4 juin 2010

Bien nommer les classes et les méthodes d’une API

Pour les classes, cela DOIT être facile...

Nommer une classe est normalement simple : il suffit de choisir un terme suffisamment général et décrivant le mieux la notion gérée par cette classe. Si la classe est bien conçue, et qu’elle respecte le principe de responsabilité unique, la nommer ne devrait pas présenter de difficultés.
Si lui trouver un petit nom s’avère difficile, ou qu’aucun nom ne paraît raisonnablement satisfaisant, il est probable que cette classe fasse trop de choses. Il n’y a alors qu’une seule chose à faire : la tronçonner ! Une autre astuce est de s’imposer de commenter la classe en une seule phrase. Si cette phrase est impossible à écrire, ou si elle n’a rien à voir avec le nom choisi, il faut changer le nom, ou bien découper la classe.

... c’est pour les méthodes que ça se complique !

Nommer correctement les méthodes publiques d’une classe a son importance. Récemment, j’ai dû enrichir les API d’un de nos logiciels. Celles-ci sont destinées à des développeurs tiers qui éventuellement ne font pas partie de notre société. Pas question donc de laisser des ambigüités ou des incohérences. Et lorsque on est en présence d’un package contenant des dizaines de classes, et que chacune d’entre elles comprend une ou plusieurs dizaines de méthodes, on se retrouve donc à fournir plusieurs centaines de méthodes, et quelques règles s’imposent :

Utiliser l’anglais : ne connaissant pas à priori quelle sera la nationalité des développeurs qui utiliseront l’API, il faut s’imposer la langue internationale de l’informatique : l’anglais.

Débuter les noms par un verbe indiquant aussi précisément que possible le type d’action réalisée :
    countUsers() : compte le nombre d’utilisateurs
    isExpired() : indique si le compte-utilisateur est expiré

Combiner des mots entiers jusqu’à décrire l’action réalisée par la méthode. 
    getExpirationDate() : retourne la date d’expiration
    notifyAllClients() : notifie tous les clients

Eviter les informations inutiles : éviter de faire porter au nom de la méthode une information non indispensable, ou bien disponible ailleurs.
Ex : si une méthode renvoie tous les employés d’un service, et qu’elle s’applique soit sur un objet Service, soit qu’elle prend un objet Service en paramètre, il est inutile de l’appeler getEmployeesByService ; getEmployees est suffisant.

Ne pas pas utiliser le mot « And » : si le recours au mot « And » est requis, c’est que la méthode à nommer réalise plusieurs actions. Dans ce cas, il faut la tronçonner. En effet, le principe de responsabilité unique s’applique à tous les niveaux, y compris au niveau d’une méthode.

Conserver la même logique dans toute l’API : ce qui est important, ce n’est pas de se faire des nœuds au cerveau pour savoir si une méthode qui met à jour un objet métier doit commencer par update ou modify. En revanche, ce qui est important, c’est de faire un choix, et de l'appliquer à travers toute l'API.

Bien-sûr, ces quelques règles ne font pas le travail à la place des développeurs, et elles peuvent être complétées. Mais les respecter m’a permis de produire une API cohérente ce qui au final facilite le travail des utilisateurs.

lundi 8 février 2010

Comment assurer la non régression fonctionnelle lors d’une migration technique ?

Fini le weekend, les soirées arrosées, les grasses matinées, et les fantasmes futuristes que l’inventeur de SixthSence a fait naître dans ma tête. De retour à la réalité du lundi matin, et au projet qui m’attend : organiser le redéveloppement d’un de nos logiciels écrit en Java/JSP vers une architecture ou la partie serveur sera en J2EE (Hibernate, Spring, etc.) et la partie cliente en technologie Adobe Flex.

Pour rendre le projet plus intéressant, ajoutons que nous n’avons ni spécification fonctionnelle, ni documentation utilisateur, que les plans de tests sont pauvres, qu’il n’existe aucun script de test automatique, et qu’accessoirement, je suis loin d’être un expert du monde Java et je découvre le Flex ! La première pensée qui me vient à l’esprit est… vivement vendredi soir !

A vrai dire, les aspects techniques ne me font pas vraiment peur. L’équipe de développement tient la route, et elle produira les tests unitaires ! Ce qui me cause souci, c’est la qualification fonctionnelle et les risques de régressions. Comment les éviter ?

La matrice de compatibilité va me dicter une partie de la réponse. Notre logiciel doit pouvoir tourner sur 3 SGBD, 3 serveurs d’applications, Windows, Linux, et le plus grand nombre possible de navigateurs Internet. Bien entendu, j’échapperai à certaines combinaisons, genre SQL Server sous RedHat :-), mais tout de même, cela fait quelques dizaines de possibilités à explorer. Dans ces conditions, il n’y a qu’un seul moyen d’être exhaustif, c’est de passer par des outils d’automatisation des tests.

Concernant la qualification fonctionnelle, tout reste encore à construire. Comme je l’ai dit précédemment, l’application historique n’est pas accompagnée de spécifications fonctionnelles qui soient utilisables. Une option pourrait être d’entamer une phase de rétro-ingénierie visant à produire des spécifications, puis à implémenter selon ces spécifications et enfin à tester pour vérifier la conformité des développements. Mais avec ce système, toute erreur introduite durant la tâche rétro-ingénierie se transforme en régression dans l’application finale. Pire encore, les bugs de l’application historique seraient transposés dans l’application cible ! Ce n’est donc pas satisfaisant.

Pourtant, ce que je veux faire est simple : il faut que la même utilisation produise le même résultat dans les deux applications. Et si pour une fois la solution était aussi simple ? Produire des scénarii de tests, les dérouler sur les deux applications, et comparer les résultats : s’ils sont identiques, tout va bien ; s’ils sont différents, alors il faut regarder pour comprendre de quel côté est le bug, et corriger si besoin.

Il ne me reste plus qu’à me mettre en quête des outils adaptés, mais ça attendra demain!

samedi 6 février 2010

Le futur a déjà commencé

Pranav Mistry est l'inventeur de SixthSense, un équipement qui permet des interactions entre le monde des données et le monde réel. Sa vidéo de présentation est tellement époustouflante que j'ai du la regarder 3 fois de suite.
Avec des tels génies, on peut se dire que le futur a déjà commencé, et c'est tant mieux !