Trivabble continue à évoluer


  • Prédateur

    Trivabble est un jeu de Scrabble en ligne que j’ai commencé en 2016 pour que les membres éparpillés de ma famille puissent jouer ensemble.

    Trivabble

    Sommaire

    Les critères :

    • le plus simple à utiliser qui soit, si possible sans inscription ;
    • fonctionnant au moins sur GNU/Linux, Windows et iPad ;
    • idéalement, c’est libre.

    J’ai fini par écrire mon propre jeu, sous licence libre AGPL. Je l’ai mis en place sur mon serveur, et je l’ai plus ou moins laissé tourner et oublié. Puis, il y a environ trois semaines, j’ai commencé à recevoir des courriels de remerciements, et quelques rapports de bogues et demandes de fonctionnalités. Je me suis dit que c’était le moment idéal pour donner à ce jeu un peu d’amour et ces derniers week‑ends, j’ai travaillé sur le jeu. On pourrait voir cette dépêche comme la présentation d’une nouvelle version, mais je n’ai jamais réfléchi sérieusement à comment gérer les versions.

    Principe du jeu

    On lance le jeu, on donne son nom et c’est parti pour jouer. On peut rejoindre d’autres personnes en renseignant un code de partie affiché dans la page.

    Il n’y a pas de règle implémentée. Le jeu fournit une zone de discussion en ligne, un sac de pièces et un plateau commun, un chevalet pour chaque joueur et les gens font ce qu’ils veulent avec. Ils pourront jouer au Scrabble, mais s’ils veulent se faire un Speed Trivabble où les joueurs jouent leurs pièces le plus vite possible, ou s’ils veulent faire des dessins avec leurs pièces sur le plateau, rien ne les en empêche — mais qu’est‑ce que le Speed Trivabble ? Un jeu dont les règles restent à inventer. :-P

    Nouvelles fonctionnalités visibles

    • le jeu est maintenant centré sur la page ; c’est tout bête, pas indispensable, mais c’est probablement plus agréable ;
    • les joueurs peuvent maintenant montrer le contenu de leur chevalet aux autres joueurs ; c’est une fonctionnalité qu’on m’a demandée — comme ça, on peut plus facilement aider ses adversaires quand ils sont bloqués ;
    • il est maintenant possible d’indiquer à qui c’est de jouer ; tout bête, mais quand on est à trois ou quatre, ça peut devenir compliqué de savoir où on en est — c’est aussi une fonctionnalité qu’on m’a demandée ;
    • le jeu est plus facile à utiliser sur un téléphone ainsi que sur une tablette Android : le jeu ne défile plus quand on essaie de bouger une pièce.

    Évolutions sous‑marines

    Le travail de ces dernières semaines était surtout invisible.

    Travail sur la rétro‐compatibilité

    J’ai pu observer que les gens laissent leur page ouverte, ou que leur navigateur ne recharge pas systématiquement les fichiers du jeu (normal, il y a une gestion du cache).

    Je fais mon possible pour qu’une version ancienne du jeu sur navigateur continue à tourner avec les dernière versions du serveur. Le jeu annonce maintenant sa version au serveur, et il existe maintenant un mécanisme avec lequel le serveur peut demander au client de se recharger.

    Par ailleurs, tout est fait pour que le client soit silencieux en cas de panne brève de connexion ou du serveur, si le joueur ou la joueuse n’essaie pas d’interagir avec le jeu à ce moment‑là. Sinon, il bloquera l’utilisation de la page et affichera un message invitant le joueur à patienter un peu. Le client se reconnecte dès que le serveur est à nouveau en route ou que la connexion est à nouveau disponible. Ça rend les mises à jour du serveur plus faciles.

    Dernière modification d’une partie

    Le jeu sauvegarde en permanence son état. Ainsi, on peut le redémarrer ou il peut planter sans que les gens ne perdent leur partie. Pour le moment, on peut quitter une partie et la retrouver dans le même état plus tard et ce « plus tard » n’est pas borné. Si vous aviez commencé une partie en 2016, vous pouvez la retrouver telle quelle maintenant.

    Cependant, je me suis rendu compte d’une utilisation de plus en plus grande du jeu ces derniers temps en voyant le fichier de sauvegarde grandir. On est passé de 100 Kio au début du mois de mars à 1,5 Mio aujourd’hui. Par conséquent, la question du ménage se pose : je vais peut‑être, devoir limiter ce temps à un moment donné. J’ai donc commencé à enregistrer, pour chaque partie, la date de la dernière modification. On verra plus tard comment j’utilise cet enregistrement : est‑ce que je nettoie toutes les parties qui ont plus d’un mois sans accès ? Pour l’instant, la question ne se pose pas, mais les outils sont là au cas où.

    Communications

    Un des bogues rapportés depuis quatre ans maintenant est que, parfois, une pièce disparaît ou se transforme. Source de fous‑rires ou de frustration, je n’ai malheureusement pas pu observer le problème moi‑même jusqu’à très récemment, et si le problème est avéré, il n’est pas encore reproductible. Ce bogue m’a conduit à me questionner sur la stabilité des communications entre le navigateur des joueurs et le serveur.

    J’ai donc passé beaucoup de temps sur le code lié aux communications. Jusqu’à maintenant, les communications étaient gérées avec des requêtes courtes pour l’envoi (quand une pièce est déplacée par exemple), et du « long polling » pour la réception : des requêtes HTTP qui ne se finissent que quand elles plantent ou que le joueur quitte la partie. Tout un mécanisme était en place pour délimiter les messages, pour se reconnecter en cas d’erreur, etc. Plus particulièrement, les messages, des objets JSON, étaient préfixés par leur taille.

    Je me suis penché sur les autres techniques de communications : les Server‑sent events et les WebSockets.

    Les Server‑sent events (SSE)

    Les SSE remplacent avantageusement ce mécanisme de long polling : chaque message est délimité par deux retours à la ligne. Le navigateur fournit un objet EventSource qui gère lui‑même les coupures de connexion et fournit un bel évènement message qui permet de récupérer chaque message sans difficulté.

    Les WebSockets

    Les WebSockets sont une autre bestiole. Comme me le disait une utilisatrice par courriel :

    « J’oubliais : on s’est interrogés sur les webSockets, mais finalement mon compagnon me charge de vous dire qu’en cette saison, on ne devrait pas en avoir besoin. »

    J’ai quand même étudié la question. Les WebSockets ont un gros avantage : ils permettent de n’utiliser qu’un canal de communication pour les envois et les réceptions. Côté navigateur, pas trop de problèmes : on utilise l’objet WebSocket qui va bien. Le serveur, lui, est écrit en JavaScript avec Node.js et, là, c’est une autre paire de manches. Je veux limiter au maximum les dépendances sur lesquelles mon code dépend, et les WebSockets ne sont pas pris en charge nativement. Pour l’instant, le serveur ne dépend de rien d’autre que de Node.js, et je ne souhaite pas rajouter une dépendance pour les raisons suivantes :

    • le déploiement sans dépendance est très simple : on copie les fichiers et ça marche ;
    • ajouter une dépendance, ça veut dire adopter un gestionnaire de paquets du style NPM ou Yarn, faire un package.json, gérer les mises à jour des dépendances, etc. ;
    • ajouter une dépendance NPM, c’est ouvrir une boîte de Pandore : on en installe une, qui dépend d’une centaine d’autres bibliothèques, et au bout de deux ou trois comme ça, on se lève un beau matin, et on réalise qu’on a un node_modules de 500 mégaoctets et qu’il faut prendre un serveur avec plus d’espace disque rien que pour jouer au Scrabble.

    J’ai donc implémenté moi‑même la prise en charge des WebSockets au‑dessus du module HTTP fourni par Node.js, en lisant la documentation. Au final, c’était très intéressant de comprendre en profondeur comment ça fonctionne, et de se rendre compte que ce n’est pas si sorcier. Si cela vous intéresse, je pourrai essayer d’écrire un journal sur le fonctionnement des WebSockets.

    Conclusion

    Trois mécanismes sont maintenant en place et fonctionnent dans Trivabble : les WebSockets, les Server‑Sent events et le long polling traditionnel, avec un système de repli :

    • si les Websockets sont disponibles, on les utilise (et pour le moment, je les désactive en production, je n’ai pas encore assez de recul pour les laisser actives) ;
    • sinon, ou si l’on se rend compte qu’elles ne fonctionnent pas, on utilise les server‑sent events ;
    • si les server‑sent events ne sont pas disponibles (Edge et Internet Explorer, par exemple), on se rabat sur du long polling. Pour être honnête, le mécanisme de long polling n’est encore là que parce qu’il ne pose pas de problème de maintenance.

    Une fois que la communication est établie, que ce soit côté serveur ou côté navigateur, la gestion est transparente et le type de communication est totalement abstrait. J’ai également découvert que Node.js, avant la version 13, par défaut, ferme automatiquement les connexions HTTP au bout de deux minutes. J’ai donc supprimé cette fermeture automatique. Le lendemain de la mise en place de cette correction, j’ai eu des plantages dus à une limitation du nombre de processus Apache maximal autorisé trop petite, j’ai donc modifié la configuration d’Apache pour autoriser un plus grand nombre de connexions simultanées.

    Le bogue de la pièce qui disparaît ou qui se transforme est certainement toujours là et je ne connais pas encore la cause de ce dysfonctionnement. Il faudra probablement repenser la manière dont sont faites les communications pour fournir certaines garanties que la manière actuelle de faire ne fournit pas.

    En attendant, le code est plus tolérant aux erreurs des deux côtés. J’ai testé les disparitions inopinées de connexion au serveur, et j’ai testé mon implémentation des WebSockets côté serveur avec des killall -s SIGKILL chromium (Firefox étant mon navigateur principal, je ne peux me permettre ce genre de fantaisies avec lui, pardi !).

    Maintenance du code

    Attention, cette section est technique, n’hésitez pas à la passer si JavaScript n’est pas familier pour vous.

    Au tout début du projet, j’utilisais ESLint pour vérifier le code. Puis j’avais abandonné et maintenant c’est reparti, j’ai la vérification en temps réel dans l’éditeur de code. J’utilise à présent let et const pour déclarer les variables, et l’utilisation de var est dorénavant interdite dans le code. J’utilise également les for..of, bien pratiques pour itérer les éléments d’un tableau.

    Malheureusement, let et const pètent la compatibilité avec Safari 9, la version de Safari de l’iPad 2. Alors, j’ai un bon vieux sed dans le code qui déploie le jeu pour remplacer let et const par var. Par ailleurs, for..of ne fonctionne pas sur les listes de nœuds renvoyées par les fonctions querySelectorAll() ou getElementsByClassName dans Safari 9 ; donc, les précautions suivantes s’imposent :

    // Éviter, ça casse sur l’iPad 2 for (const node of parent.querySelectorAll()) { // ... } // ok for (const node of [].slice.call(parent.querySelectorAll())) { // ... }
    

    Et par conséquent, pas de fonctions flêchées ou de paramètres par défaut. Je pourrais utiliser Babel, mais encore une fois, le gain apporté pour pouvoir utiliser toutes les dernières fonctionnalités de JavaScript est très largement perdu par l’obligation de rajouter une dépendance au projet, une étape de compilation, la configuration de Babel, et obtenir un code illisible en production.

    Évolutions futures

    Je prévois de séparer toute la logique spécifique au jeu de Scrabble du reste, pour pouvoir proposer des jeux différents sur le même modèle. J’ai un jeu de dames qui est l’adaptation d’une copie ancienne de Trivabble. Je prévois ainsi de récupérer ce travail et le rendre public, et de proposer, dans le même esprit, un plateau pour les échecs.

    Je prévois également de continuer à réfléchir sur comment éviter les problèmes de cohérence qui sont peut‑être à l’origine de ce bogue de disparition occasionnelle de pièces.

    Conclusion

    Je n’ai pas les nombres exacts sur l’utilisation du jeu mais, a priori, depuis le 10 avril, on tourne entre trente et cent numéros de parties uniques par jour (un numéro de partie correspond à une partie, ou plusieurs si les gens enchaînent plusieurs parties avec le même numéro), avec un pic à trois cent soixante pour le lundi de Pâques.

    N’hésitez pas à en parler autour de vous, c’est le bon moment. :-)

    Télécharger ce contenu au format Epub

    Commentaires : voir le flux atom ouvrir dans le navigateur

    https://linuxfr.org/news/trivabble-continue-a-evoluer


Log in to reply