Tester, encore et toujours tester

Il y a quelque temps j’ai écrit un article, poliment intitulé Je suis un vieux con, où je râlais pour la sempiternelle fois sur une très mauvaise expérience : je n’ai même pas pu consulter le contenu d’un article de blog, à cause d’une combinaison de facteurs divers. Mon navigateur affichait un en-tête de page et rien d’autre, le code source de la page montrait de nombreux liens de navigation, mais de contenu, point.

Ces facteurs, en résumé, étaient :

  1. le contenu de la page ne peut pas s’afficher sans JavaScript,
  2. le JavaScript en question est sur un serveur tiers,
  3. le serveur tiers est sur une plateforme bloquée par mon navigateur.

Les réactions de mon entourage ont été assez habituelles :

  • « Chez moi ça marche. »
  • Variante : « Moi aussi j’ai Firefox mais chez moi ça marche. »
  • « Désactive tes bloqueurs ! »

Alors, oui, j’aurais pu décider de ne rien bloquer, et de laisser Google, Facebook et consorts écouter l’ensemble de mon activité en ligne. Mais comme nous ne sommes pas ici pour débattre de ce que je bloque ou pas, ni des opinions des uns ou des autres sur le sujet (sinon ça va durer un moment), essayons de nous concentrer sur les questions opérationnelles1.

Au passage, avant qu’on ne l’objecte, c’est un très gros site avec beaucoup de moyens, donc ce n’est pas une question de moyens mais d’approche. Cette expérience montre qu’il a manqué (volontairement ou non) un certain nombre de cas à tester dans la procédure que les gens chargés du développement et du déploiement du site de blog en question ont écrite.

En préparant cet article, j’ai recherché un peu ce que dit le Web des blocages de certaines plateformes, et je suis tombé sur ça :

ajax.googleapis.com is a CDN repository for the popular jquery javescript functionality plus others that modern websites utilise.

If you block this then you will stop the website functioning as it was designed to work.

Pour résumer la pensée du contributeur : c’est la conception du site qui fait qu’il ne marchera plus si un serveur tiers est bloqué, donc il suffit de ne pas bloquer tel ou tel serveur tiers et ça devrait aller.

N’oublions pas cependant que tout ce que nous faisons est au service de la personne qui consulte nos sites, personne qui la plupart du temps ne saura même pas que quelque chose est bloqué, ni comment contourner le problème (je reçois tous les jours des mails de vrais-clients-du-vrai-monde, je constate que ce n’est pas le métier de tout le monde de savoir débugger une page web, c’est fou quand on y pense).

On ne peut pas tout prévoir

La règle de base dans notre métier, c’est qu’on ne peut pas tout prévoir. J’ai souvent entendu des personnes en conférence appeler le Web « l’environnement de développement le plus hostile qui soit ». C’est vrai qu’entre le nombre de résolutions différentes, de navigateurs différents, de faux positifs (tel navigateur dit comprendre le SVG mais pas s’il est utilisé en image de fond — hein, quoi ?), de restrictions techniques (bande passante, sécurité du système d’information…), on est très loin du « write once, run everywhere »2 .

Par exemple, on ne peut pas prévoir que Firefox proposera plusieurs niveaux de blocage, et que l’un d’entre eux bloquera les serveurs de Google qui envoient le JavaScript à la page. On ne peut pas prévoir que si ce n’est pas Firefox lui-même, ça peut être une extension de protection de la vie privée, un réglage dans les proxies du système d’information — voire une bête lenteur du réseau !

Oui, c’est le premier problème : la plupart du temps, les tests sont réalisés dans la situation idéale. Au mieux, les ressources sont mises en cache sur la machine du développeur. Au pire, il faut aller les télécharger, mais le développeur est souvent installé bien au chaud sur les tuyaux : ça va vite, tout va bien.

Et les bloqueurs en tous genres ? Peu nombreux sont les gens qui en utilisent, si je regarde autour de moi.

En réalité, on préfère inconsciemment ne pas envisager que ça ne marchera pas, c’est psychologique : on n’aime pas être face à l’échec, c’est humain. Ou alors on y pense et puis on le refoule rapidement, on se dit que tant pis, la personne rechargera la page, elle est habituée, le Web est une loterie où on ne gagne pas à chaque fois.

Variante : on n’a pas le temps de penser à tout ça, et puis finalement ça concernera qui, à part deux ou trois personnes qui l’ont bien voulu et doivent être en mesure de contourner le problème. C’est un peu comme l’accessibilité, finalement : tant que je ne connais pas de près une situation bloquante, ça reste théorique et lointain.

Penser « chemin critique »

Prenons un cas concret de développement : mettre un produit dans un panier et aller jusqu’au bout d’une commande. Quand je teste, je dois m’assurer que le strict minimum, c’est que cette action puisse être menée à son terme. C’est ce qu’on appelle le « chemin critique ». Les autres actions qu’aurait pu proposer la page produit (les produits connexes, les « vous aimerez aussi », les zones de rebond, etc.) ne sont pas aussi critiques pour mon site marchand : si elles tombent en panne, la commande peut toujours avoir lieu.

Dans le cas de l’article de blog, le « chemin critique », c’est : mon utilisateur vient sur cette page pour y lire un contenu, le reste est additionnel. On aurait pu faire le choix inverse, afficher le contenu dans la page (c’est souvent à ça qu’elles servent, d’ailleurs, les pages : à afficher des contenus !) et utiliser JavaScript pour enrichir la page, une fois le strict minimum chargé.

En faisant ce dernier choix, on se prémunissait contre tous les écueils dont je parlais plus haut. Pas de JavaScript ? Le contenu s’affiche ! Une lenteur réseau pour aller chercher les scripts tiers ? Le contenu s’affiche ! Un bloqueur de publicités, une extensions respectueuse de la vie privée bloque un élément ou l’autre ? Le contenu s’affiche !

Assurons-nous que quoi qu’il arrive ce chemin critique est satisfait. Et si votre chef de projet trouve que c’est du zèle inutile, il suffit de se demander si on préfère que ça marche à tous les coups ou si on doit charger un tombereau de bibliothèques logicielles avant que ça marche peut-être.

Scripts tiers et asynchronicité

Oui mais vous me direz : et les sites qui ont absolument besoin de JavaScript pour fonctionner ? J’y viens. Un jour j’ai travaillé sur un jeu en ligne animé et compliqué. Dans ce projet les scripts étaient de deux types :

  1. ceux nécessaires au fonctionnement de l’application,
  2. ceux utilisés pour les statistiques.

Du fait de la nature de JavaScript, les navigateurs ont tendance à télécharger tous les scripts pour les lire et savoir comment les exécuter. Dans notre cas, les premiers sont à charger le plus vite possible, les seconds sont souhaitables mais pas nécessaires à l’exécution.

Ça tombe bien : l’attribut async de la balise script est là pour ça (voir script sur MDN), pour expliciter que ce fichier peut être chargé de manière asynchrone. Il permet au navigateur de ne pas attendre que le script concerné par cet attribut soit chargé avant de charger et d’interpréter les autres scripts.

Testez que tous les scripts critiques sont chargés tout de suite (et si possible qu’ils ne soient pas sur un CDN, et si possible qu’ils soient peu nombreux et légers à charger), et vérifiez bien que tous les scripts tiers sont chargés en asynchrone.

Une méthode de test

Je propose la méthode de test suivante :

  • Bloquer les services tiers : si je les bloque tous, je me prémunis contre quelque blocage qui existe chez les personnes qui consultent le site, qu’il soit volontaire ou non — il peut même être accidentel.
  • Désactiver JavaScript : sauf cas particulier (un composant applicatif), que se passe-t-il si je désactive JavaScript ? Il existe des méthodes pour écrire des parcours sans JavaScript puis d’intercepter les événements pour les enrichir3.
  • Désactiver les feuilles de styles : on ne vous demande pas de jouer au CSS Naked Day4 pour le plaisir, mais là encore, selon les situations, si vous vous appuyez sur les feuilles de styles dans vos scripts, un bon moyen de voir à quel endroit votre développement va casser est de les désactiver volontairement.

J’en conviens, tout ça paraît bien radical. Il y a une vingtaine d’années je parlais avec quelqu’un qui travaillait dans le domaine du jeu vidéo et qui me parlait de la manière dont sont éprouvés les jeux5, ce que nous voyons ici est terriblement plus simple, estimons-nous heureux !

Mais ça a le mérite d’être solide. Et encore, cette méthode est incomplète. On pourrait aussi imaginer ralentir le débit réseau, bloquer aléatoirement tel script et pas tel autre, que sais-je encore.

Le mot de la fin

Dans leur livre, Design for Real Life (en anglais), Eric Meyer et Sarah Wachter-Boettcher résument assez bien le problème :

[W]e often hear, “We’re designing for the 90%, not the 10%.” That’s classic edge-case thinking : a shorter way of saying, “That’s a difficult use case that I don’t want to think about.” That’s why we think the concept of stress cases is so valuable.

Grossièrement traduit, : on entend souvent qu’on conçoit les services pour le plus grand nombre. Les cas marginaux, c’est plus simple de ne pas s’en préoccuper. Les auteurs proposent de remplacer « marginaux » (“edge cases”) par « difficiles » (“stress cases”), ce qui leur donne une portée bien différente dans la conception.

Pour résumer : au lieu de penser que les situations qui posent problème sont à la marge, traitons-les prioritairement. Si celles-ci fonctionnent, les situations les plus simples fonctionneront d’autant mieux. Répétons-le, nos châteaux de cartes sur le Web peuvent casser, et même, la plupart du temps, ils casseront, que nous le voulions ou non. Il faut donc que j’intègre le plus possible l’imprécision du résultat dans mon développement.

Notes

Un grand merci à Delphine Malassingne et Véronique Lapierre pour leur relecture attentive.

  1. Oui c’est un terme un peu grandiloquent mais je n’en avais pas d’autre sous la main.
  2. « Écrivez une fois, exécutez partout. »
  3. Jeremy Keith a popularisé cette approche sous le nom de Hijax, un mot-valise entre hijack (intercepter) et AJAX. C’est une méthode d’amélioration progressive fort populaire en son temps !
  4. Il y a quelques années, des avocats des standards ont inventé le CSS Naked Day, où les propriétaires de sites web désactivaient volontairement les feuilles de styles de leurs sites, afin de mettre en évidence l’importance de la sémantique HTML.
  5. « Tiens, et si je pose mon coude en vrac sur le clavier et que je clique en même temps, le jeu plante-t-il ? Si oui, corrigeons le bug. » Naïvement j’ai demandé si des gens faisaient ça, il faut croire que tout arrive.

2 commentaires sur cet article

  1. Nico, le mercredi 9 décembre 2020 à 19:02

    Déjà, rien que de naviguer avec un uMatrix activé fait énormément relativiser sur les phrases « oui, ça se chargera bien ».
    Et si la dépendance tombe ? Plante ? Est injoignable ? Lente ?

    J’avoue que ça me fait mal de tomber régulièrement sur des sites qui ne se chargent tout bonnement pas, juste parce que le chemin critique n’est pas là. Genre tomber sur un loader infini pour un article de blog… merde quoi ! (certes j’assume que j’utilise un truc assez violent qui bloque pas mal de choses… mais genre… au moins quelque chose d’affiché quoi !)

    Dans un autre genre : un test amusant que je faisais quand je testais certaines intégrations y a qq années : un BrowserSync qui donc synchronise un écran avec pleins d’autres, qq écrans/périphériques divers (smartphone/tablette/divers écrans/navigateurs/résolutions… si tu es joueur avec différents zooms), et c’est parti :
    tu contrôles depuis un écran, et tous les autres font la même chose => tu finis par obtenir des cas totalement délirants où un bouton invisible sur desktop est activé sur desktop (et inversement), et tu vois des situations qui ne devraient PAS se passer.

    En gros, que se passe-t-il quand qqch qui n’est PAS supposé arriver… arrive quand même. Hé bien, c’est assez sympa et riche d’enseignements. :)

  2. Lamecarlate, le lundi 6 septembre 2021 à 08:40

    Au gré de mon flux RSS je (re)tombe sur cet article. D’abord je me suis dit « chic, un nouvel article de Stéphane, c’est trop bien, je vais en parler au boulot, mettons-ça dans mon Wallabag – ah tiens il y est déjà ? ah oui, 2020 ». Donc je me corrige « chic, un article de Stéphane, c’est trop bien, je vais en parler au boulot ! ».

    J’avais dernièrement râlé sur une page qui était *vide* de contenu parce que j’avais bloqué un script externe – mais pas si je bloquais complètement JavaScript. La raison ? L’article en question ne contenait que des images, qui étaient lazyloadées en JS, mais doublées par les mêmes images « nature » dans des balises noscript. Tellement de boulot pour ça, quoi. Et ça avait lancé une intense discussion « mais takapa bloquer les scripts, aussi »… la fatigue.