2 points par GN⁺ 2024-04-05 | 1 commentaires | Partager sur WhatsApp
  • Après avoir utilisé à la fois une SPA React et Phoenix LiveView pur, l’équipe de Sequin a conclu que l’approche la plus productive consistait à combiner LiveView et Svelte avec LiveSvelte
  • LiveView permet de créer des interfaces riches sans SPA grâce à l’état côté serveur et aux mises à jour incrémentales du DOM, mais dès qu’un état client devient nécessaire, modules JS, hooks et état LiveView se mélangent et la frontière devient floue
  • En LiveView pur, LiveView, LiveComponent et Component ont des cycles de vie, des modes de passage des props et des mécanismes de communication différents, ce qui rend le refactoring et le placement de l’état plus fastidieux qu’avec React
  • LiveSvelte fournit une frontière bidirectionnelle claire : Elixir transmet les props vers le bas et Svelte remonte les événements avec live.pushEvent
  • Dans cette combinaison, le routage, la logique métier et la préparation des données restent côté serveur, tandis que l’état de l’UI, les animations et le rendu conditionnel sont pris en charge par Svelte, ce qui réduit la complexité d’une SPA

Le modèle de développement proposé par LiveView

  • Une application traditionnelle en rendu serveur ne conserve pas d’état côté serveur et rend la page à chaque requête du client
  • Dans une SPA, le client se charge de composer la page, lit et écrit les données via une API backend, et gère l’état client avec des mécanismes comme useState de React
  • LiveView continue de confier le rendu de la page au serveur tout en conservant l’état, puis traite les actions frontend et met à jour le DOM de façon incrémentale comme une SPA
  • La complexité d’une SPA augmente parce que l’application JavaScript côté client agit en pratique comme un microservice frontend
    • Les besoins propres au frontend multiplient les routes et contrôleurs backend
    • Une requête peut traverser onMount, un appel d’API, le parsing de la réponse, le routeur, les plugs d’authentification, le contrôleur, les fonctions métier et la couche de préparation de la réponse
  • L’avantage de LiveView est de permettre une expérience client riche sans microservice frontend
    • Il est possible d’interroger la base de données à proximité de la fonction qui rend un tableau
    • Lorsqu’une nouvelle ligne arrive, on peut la pousser dans le tableau et LiveView met à jour le client
    • On obtient des interactions plus proches d’un framework frontend stateful que du rendu serveur classique où tout l’état est reconstruit à chaque requête

Les frictions rencontrées avec LiveView pur

  • L’état côté client reste inévitable

    • LiveView ne peut pas éviter la latence d’aller-retour entre le serveur et l’utilisateur
    • Pour les animations, infobulles, affichage/masquage du DOM ou désactivation de champs de formulaire, un traitement côté client devient parfois nécessaire
    • Dans un formulaire avec deux listes déroulantes dépendantes, une bonne UX consiste à désactiver immédiatement la seconde après la sélection dans la première, puis à la réactiver une fois que le serveur a renvoyé la nouvelle liste
    • Implémenter ce comportement avec LiveView seul demande de combiner plusieurs concepts
      • Le module JS de LiveView désactive la seconde liste lors du changement de la première
      • Un hook enregistre un écouteur d’événement sur la seconde liste, puis le backend envoie une action de réactivation
      • Si la réactivation doit être conditionnelle, l’état LiveView peut aussi entrer en jeu
    • Quand JS, hooks et état LiveView sont utilisés ensemble, une partie de l’état du DOM se retrouve hors de LiveView, ce qui rend difficile l’adoption d’un schéma cohérent
  • Des frontières d’état différentes de React

    • React gère la plupart des transitions avec deux concepts centraux, l’état et les actions, et la frontière entre état du DOM et état du composant y est relativement nette
    • Comme il n’y a pas de latence entre action client et état client, React peut traiter actions et transitions dans un paradigme d’état
    • L’état de LiveView se situe côté serveur, il faut donc tenir compte de la latence entre action client et état serveur
    • Dans l’exemple d’un champ de saisie, React passe par le chemin de l’état avant même que le caractère soit affiché, et le composant se rerend à chaque frappe
    • LiveView est plus proche d’un modèle où l’utilisateur modifie d’abord le champ, puis le serveur en prend connaissance un court instant plus tard et réagit ensuite
    • Quand la latence est quasi nulle, cela ressemble à React, mais plus elle augmente, plus la différence entre les deux modèles devient évidente

La complexité créée par trois types de composants

  • LiveView propose trois types de composants : LiveViews, LiveComponents et Components
  • LiveViews et LiveComponents se rapprochent de composants stateful de React, tandis que Components se rapproche de composants fonctionnels
  • LiveView est toujours le composant parent de plus haut niveau, sous lequel sont rendus LiveComponents et Components
  • Dans React, on peut passer facilement d’un composant stateful à un composant fonctionnel en ajoutant ou retirant le hook useState
    • Les deux reçoivent les props de la même manière
    • En dehors de l’état, leur ensemble de fonctionnalités est identique
    • L’enregistrement des événements DOM et leur traitement fonctionnent aussi de la même façon
  • Dans LiveView, les différences entre les trois types de composants sont importantes, ce qui rend fastidieux le refactoring d’un LiveView en LiveComponent
    • La syntaxe de rendu et de passage des props diffère entre LiveViews et LiveComponents
    • Leur cycle de vie est différent
    • Les options de communication diffèrent : on utilise send pour les LiveViews et send_update pour les LiveComponents
    • Les LiveComponents ne sont pas des processus et ne peuvent donc pas interagir avec les autres parties du système comme le font les LiveViews

Les limites de LiveComponent

  • Un LiveView est un processus Elixir : il possède un pid, un état et une inbox, et peut se comporter comme les autres processus du système Elixir/OTP
  • Dans un LiveView, on peut utiliser pub/sub pour s’abonner à des changements à l’échelle du système
  • Un LiveComponent n’est pas un processus autonome, mais un module invoqué par LiveView
  • Comme le processus parent LiveView conserve l’état des composants enfants, c’est lui qui doit aussi gérer le routage des messages vers les LiveComponents enfants
  • Pour que les LiveComponents disposent d’une gestion d’état et d’un traitement d’actions véritablement indépendants, chacun devrait être un processus, ce qui n’est pas le modèle actuel
  • En pratique, même lorsqu’on veut envoyer un événement ou une action à un LiveComponent, il n’existe pas de bonne méthode, et il devient ambigu de savoir si send_update doit servir à transmettre une action ou à appliquer un patch d’état
    • S’il sert à appliquer un patch d’état, il faut aussi réfléchir à la manière de distinguer montage et mise à jour dans la clause update

La frontière créée par LiveSvelte

  • LiveSvelte permet de rendre des composants Svelte dans LiveView
  • Dans le render de LiveView, on peut encoder des structures de données Elixir en plain maps pour le frontend, puis les transmettre comme props à un composant Svelte
  • Le composant Svelte reçoit les props avec export let et communique avec LiveView via la prop live fournie par LiveSvelte
  • Côté Svelte, on peut envoyer des événements au serveur avec live.pushEvent
    • Dans l’exemple, un bloc réactif de Svelte envoie l’événement "form_updated" au serveur quand form change
    • LiveView décode ensuite les paramètres frontend dans handle_event("form_updated", ...) et met à jour le changeset
    • Les erreurs de validation du changeset sont renvoyées au frontend via la prop errors
  • Les données descendent d’Elixir vers Svelte sous forme de props, puis remontent de Svelte vers LiveView via des événements WebSocket
  • Le processus LiveView peut à tout moment mettre à jour les props pour provoquer un rerender du composant Svelte

Les propriétés clés de l’association LiveView + Svelte

  • Le point central de cette combinaison est qu’un processus backend stateful et un composant frontend stateful fonctionnent ensemble
  • Trois propriétés soutiennent cet assemblage
    • Le backend contrôle les props du composant frontend
    • Le frontend et le backend ont tous deux un état
    • Les deux côtés disposent d’un canal privé de communication bidirectionnelle permettant à chacun d’initier des messages
  • La première propriété est rendue possible par le mode de rendu de LiveView
    • Le résultat du rerender serveur est automatiquement poussé vers le client puis appliqué
    • Le serveur peut mettre à jour les props d’un composant comme le ferait un composant parent en JS
  • La deuxième propriété découle du fait que LiveView est un processus Elixir
    • Un processus Elixir est une manière d’encapsuler l’état
  • La troisième propriété est rendue possible par la connexion WebSocket persistante fournie par LiveView

Différences avec une SPA

  • Tout le routage navigateur est géré par le backend, ce qui simplifie l’architecture
    • Dans une SPA classique, il faut maintenir deux types de routes : les routes navigateur et les routes API
  • Le backend conserve l’état et connaît la route actuelle ainsi que la ressource en cours de manipulation
    • Chaque action peut être traitée comme une modification de l’état du backend lui-même, au lieu de tout reconstruire depuis zéro
  • La communication entre frontend et backend est privée et étroitement couplée
    • Elle n’augmente pas le nombre de routes publiques du serveur pour prendre en charge des appels RPC liés à un composant unique
    • Lorsqu’on voit un pushEvent côté client, on sait que le handler correspondant se trouve dans le module Elixir avec lequel il collabore
  • La fonctionnalité se répartit généralement dans deux fichiers
    • Le module backend appelle des fonctions backend comme les requêtes base de données
    • Le frontend importe les composants et les styles
    • Les allers-retours frontend/backend ne traversent ni un module API, ni un routeur, ni une pile de contrôleurs
  • La procédure de communication est aussi réduite
    • Le backend peut signaler des changements au frontend par simple mise à jour des props
    • Le frontend peut envoyer un pushEvent sans gérer jetons expirés, timeouts ni handlers de panne
    • Si le WebSocket est ouvert, le serveur fonctionne ; s’il est fermé, LiveView affiche une bannière globale « disconnected »

Séparation des responsabilités et structure du code

  • Avec cette architecture, on a l’impression que le microservice frontend a disparu
  • La logique métier reste côté backend
    • La manière de charger les données
    • Les données à charger
    • Les règles de tri et de filtrage
    • Les validateurs
  • Le code frontend Svelte devient plus simple
    • Des blocs if/end pour le rendu conditionnel
    • Des animations
    • De simples fonctions pushEvent pour parler au serveur
  • Dans un frontend de SPA classique, il peut y avoir beaucoup de logique map, reduce, filter pour traiter les données serveur, préparer les données d’affichage et préparer les données à renvoyer au serveur
  • Dans une application LiveSvelte, ces traitements peuvent être effectués côté serveur
    • LiveView prépare les données dans le format attendu par le composant Svelte
    • La complexité reste dans le langage serveur, les structures de données serveur et la suite de tests serveur
  • Le LiveView et le composant Svelte sont moins deux éléments faiblement couplés que deux moitiés d’une même fonctionnalité
    • Le LiveView ne rend que ce composant Svelte précis
    • Et ce composant Svelte n’est rendu que par ce LiveView précis

Ce qui change par rapport à LiveView pur

  • L’approche LiveSvelte assume l’état frontend et les transitions d’état
  • La couche frontière entre frontend et backend devient plus claire
  • Elle permet de tirer parti du paradigme de composants mature de Svelte
  • Elle ouvre aussi l’accès à l’écosystème des frameworks JavaScript, difficile à mobiliser avec LiveView pur seul
    • Svelte fournit des primitives d’animation
  • En déplaçant davantage de responsabilités vers le frontend, elle réduit l’impression d’être coincé dans une zone intermédiaire maladroite

Pourquoi Svelte et quelle place pour LiveView

  • Le choix de LiveSvelte vient du fait qu’il n’existait pas de bibliothèque LiveView d’un niveau de maturité comparable pour React
  • Svelte est considéré comme un framework frontend léger et rapide, avec une gestion de l’état et une réactivité natives
  • Comme LiveView prend en charge une grande partie de la gestion d’état, l’état côté Svelte reste simple
  • Les capacités de template de Svelte sont également préférées à celles de React
    • On peut utiliser if/else plutôt qu’un opérateur ternaire
    • On peut définir des attributs conditionnels
  • Les runes de Svelte 5 devraient rendre Svelte plus facile à apprendre et à raisonner
  • LiveView brille surtout comme backend-for-frontend capable de rendre des composants frontend, d’effectuer des mises à jour incrémentales, de maintenir un processus backend stateful et de fournir une API WebSocket

1 commentaires

 
GN⁺ 2024-04-05
Commentaires sur Hacker News
  • Un schéma souvent utilisé dans les jeux multijoueurs consiste essentiellement à exécuter le même code côté client et côté serveur
    Le code client anticipe d’abord l’état du serveur, puis quand l’état serveur arrive, il écrase l’état du client
    Dans les jeux, le client peut assez bien deviner le résultat de ses propres entrées, mais il ne connaît pas celles des autres joueurs, donc le terme de « prédiction » est bien adapté
    Mais cette approche peut aussi servir à réagir immédiatement, par exemple pour activer/désactiver un menu déroulant ou afficher un spinner de chargement, en attendant l’état serveur faisant autorité
    Il existe aussi beaucoup d’états purement client, comme les systèmes de particules ou les ragdolls, qui n’ont pas besoin de tourner sur le serveur, et avec une connexion serveur persistante, rien n’empêche en théorie de l’appliquer aussi dans un paradigme réactif

    • C’est exactement l’approche utilisée sur https://territoriez.io/
      C’est un clone de https://generals.io/ réalisé avec LiveSvelte
      C’est pratiquement un jeu de plateau et ça tourne à 2 ticks par seconde, donc il n’y a pas besoin de prédiction, mais il y a bien des mises à jour optimistes qui affichent l’état du jeu avant la mise à jour du serveur
      Si la synchronisation avec le serveur ne correspond pas, le serveur écrase l’état du jeu
      Toute la logique du jeu est dans Elixir, et pour faire de la vraie prédiction, le serveur et le client doivent partager la logique
      Sinon il faut écrire la logique deux fois, et c’est la voie directe vers la catastrophe
      Je n’ai pas étudié le sujet, mais une solution possible serait d’écrire toute la logique du jeu en gleam(https://gleam.run/)
      Gleam est compatible avec Elixir et peut aussi être compilé en JavaScript, donc en théorie le même code peut tourner côté serveur et côté client
      Cela dit, l’argument « autant tout écrire directement en js » se tient assez bien, et je serais sans doute d’accord
      Malgré tout, l’avantage est de pouvoir profiter de BEAM et de ses atouts pour les systèmes distribués en temps réel, ce qui correspond très bien aux jeux multijoueurs, hormis la partie frontend
    • Quand on joue à un jeu comme Overwatch, qui simule localement et de façon non déterministe la physique des ragdolls, on se dit que ce serait bien que ce soit mieux géré
      Quand quelqu’un meurt et que son corps est projeté ou reste coincé dans une pose ridicule, personne d’autre ne le voit, et même dans les replays on ne peut pas le revoir puisque chaque client le rend différemment
      Si ce n’est pas capturé dans un enregistrement en temps réel, c’est perdu pour toujours
      Dans un jeu parfois aussi absurde qu’Overwatch, c’est dommage que personne ne puisse partager ces moments
    • Les jeux de combat poussent ce problème de résolution de collisions à faible latence à l’extrême, au point qu’il existe tout un sous-domaine de techniques de « netcode » dédiées à l’orchestration de flux d’événements en temps réel
      https://arstechnica.com/gaming/2019/10/explaining-how-fighti... en donne une excellente explication, et on trouve des discussions associées sur https://news.ycombinator.com/item?id=34399790 et https://news.ycombinator.com/item?id=26289933
      Dès qu’on ajoute la persistance serveur, comme dans un MMO, il faut aussi prendre en compte les goulots d’étranglement d’entrée/sortie
      https://prdeving.wordpress.com/2023/09/29/mmo-architecture-s... est un billet intéressant sur cet angle, avec une discussion ici : https://news.ycombinator.com/item?id=37702632
    • Ce n’est pas simplement une mise à jour optimiste ? Ce n’est pas déjà une approche très courante depuis longtemps dans la logique côté client ?
    • Il faut l’utiliser avec prudence
      Par exemple, un formulaire live/interactif peut sembler bien fonctionner en mettant à jour des données dérivées sur la page, puis tout être annulé plus tard à cause d’une erreur serveur ou d’un problème réseau
      Pire encore, l’utilisateur peut fermer la page ou partir ailleurs sans même s’en rendre compte
  • J’aime beaucoup la combinaison LiveView + Svelte
    J’ai présenté à ElixirConf 2022 une façon de les combiner, mais ce sont les contributeurs de live_svelte qui l’ont réellement rendue exploitable en pratique
    À mon avis, les applications qui offrent une expérience utilisateur riche ont toujours besoin d’un état côté client
    Surtout quand on vit à New York, où disposer d’une connexion réseau en déplacement ne va pas de soi
    Une fonctionnalité puissante que l’article ne mentionne pas, c’est qu’avec le pubsub de Phoenix, on peut aussi pousser de manière réactive à tous les clients les changements d’état côté serveur survenus sur d’autres serveurs
    Dès qu’on doit gérer un trafic moyen ou élevé, il est assez courant d’avoir plusieurs serveurs web

    • Les réseaux mobiles ont aussi globalement une latence élevée, et il faut souvent un système de cache local-first côté client
      Si on veut une expérience à la LiveView tout en restant robuste face à un réseau instable, j’ai ajouté des bindings Svelte 5 à Triplit[1]
      On peut écrire les requêtes côté client et se synchroniser avec le serveur via WebSocket
      Ce n’est peut-être pas très séduisant pour les développeurs Elixir, mais si Svelte est au centre de l’architecture, Triplit est un bon choix
      [1] https://www.triplit.dev/docs/frameworks/svelte
    • Dans des situations où le réseau coupe par intermittence, à quel point une page LiveView reste-t-elle utilisable hors ligne ?
  • Quand de nouvelles lignes arrivent, il vaut mieux éviter de simplement les pousser dans le tableau et laisser LiveView mettre le client à jour dans des applications métier interactives
    À cause de la latence cognitive, l’utilisateur peut facilement cliquer sur le mauvais élément, envoyer un e-mail au mauvais client ou rembourser la mauvaise transaction
    L’expérience utilisateur préférable est une bannière fixe du type « Les données ont changé. Cliquez ici pour actualiser »
    En cas d’urgence, il faut rendre les nouvelles lignes en mode ajout uniquement et faire en sorte que la position de défilement ne change pas

    • Cette approche peut aussi fonctionner si l’on insère lentement les nouvelles lignes avec une animation et que l’on désactive les clics pendant l’arrivée des nouvelles données
  • Dans BeaconCMS, Svelte et LiveView sont utilisés ensemble
    Il existe clairement de bons cas d’usage où il faut un contrôle plus fin de l’interface côté client, mais il faut être prudent avant que l’équipe adopte Svelte + LiveView partout
    Même avec Phoenix, LiveView n’est pas toujours la réponse, et parfois une page rendue de façon classique suffit
    Il ne faut pas tout voir en tout ou rien
    Comme le dit l’article, il existe de bons cas d’usage pour sortir de la « manière LiveView »
    Si le temps d’aller-retour est de 1 000 ms, il faut envisager autre chose, mais pour des équipes qui ne peuvent pas avoir de serveurs géographiquement proches pour des raisons comme le coût, la gestion d’état côté client peut être une solution

  • Au lieu de gérer l’état client, il faudrait donc gérer à la fois l’état client et l’état serveur ?
    Il y a bien l’avantage de ne pas avoir à créer une autre API, mais ça ne ressemble pas vraiment à une amélioration

    • L’état d’une application web n’est pas si simple
      Il y a toujours un état que le client doit suivre et un état que le serveur doit suivre, avec en plus un chevauchement entre l’état temporaire qui peut rester uniquement en mémoire et l’état qui doit persister d’une session à l’autre
      Les façons de gérer cela sont presque infinies, et en JavaScript, comme il n’y a pas de « bonne réponse quoi qu’on fasse », on finit soit par suivre la façon imposée par le framework, soit par bricoler, autrement dit par sombrer dans le chaos
      Dans la dernière application monopage complexe sur laquelle j’ai travaillé, on faisait une synchronisation à chaque chargement de page côté client
      Tous les états locaux et toutes les ressources avaient un hash basé sur la date, et s’il différait de la valeur côté serveur, le serveur envoyait une version mise à jour
      C’était vrai aussi bien pour une simple variable que pour un énorme objet JSON, ou même pour des blobs image/audio complets
      Quand le client faisait quelque chose qui nécessitait un changement d’état côté serveur, il envoyait cette mise à jour d’état via WebSocket, et 99 % de l’application reposait sur WebSocket
      Nous n’utilisions ni framework ni pattern particuliers ; en écrivant le code, si l’on se disait « ça, c’est au serveur de le suivre », on envoyait le nouvel état au serveur dans un message, et c’était au serveur de décider s’il fallait le synchroniser au chargement de la page
      Pour ce type de gestion d’état, j’estime que c’est à peu près le mécanisme le plus simple possible
      WebSocket aide énormément pour la gestion d’état
    • Au final, j’ai l’impression qu’une forme de ce paradigme va l’emporter
      Les applications réelles ont besoin d’état à la fois côté client et côté serveur
      Le serveur doit avoir un état faisant autorité, puisqu’il ne peut pas faire confiance au client, mais le client doit aussi pouvoir réagir aux interactions utilisateur et rerendre sans aller-retour
    • Certaines choses offrent une meilleure expérience si elles sont traitées entièrement côté client
      Il ne faut pas tout faire ainsi, seulement quand cela a du sens
      Un autre point qui me plaît, c’est qu’on peut utiliser Svelte comme langage de template au lieu de Heex
    • Cela ressemble surtout à une nouvelle génération qui redécouvre ColdFusion, Web Forms, JSF, PHP, Spring et Rails
    • Cela ne diffère pas des optimisations pratiquées dans d’autres écosystèmes logiciels
      Il n’y a aucune raison de le faire si ce n’est pas nécessaire, et si cela devient nécessaire, c’est pour des raisons de performance et d’expérience utilisateur
      Si une application web comporte beaucoup d’interactions utilisateur nécessitant du JavaScript côté client, et qu’elle fait beaucoup d’expérimentations au point que les bundles changent selon les requêtes, on finit par vouloir répartir la logique entre serveur et client pour réduire la quantité de JavaScript envoyée au client
      Sinon, on se retrouve avec un bundle JavaScript de plusieurs Mo qui contient toutes les possibilités que l’application peut rencontrer
      Cela peut convenir pour une application comme la version web de Photoshop, où l’utilisateur comprend le temps de chargement initial, mais pour des applications comme Stripe ou Gmail, où l’on s’attend à un chargement immédiat, on veut réduire la latence initiale de la page
      On peut tout déplacer vers le serveur, mais comme GitHub l’a constaté, des actions utilisateur qui devraient réagir instantanément se retrouvent à nécessiter un aller-retour serveur, ce qui dégrade l’interactivité de la page
      On se heurte alors à la vitesse de la lumière et à la répartition des serveurs
      On peut aussi différer le chargement des bundles avec des choses comme async import, mais cela crée alors un problème de cascade, parce que le JavaScript chargé à la demande envoie encore une autre requête pour récupérer ses données
      Quand on a rencontré tous ces problèmes, on finit par chercher une solution qui traite facilement le problème complexe du partage de logique et d’état entre client et serveur
  • Cette approche a une limite de vitesse de la lumière au sens littéral du terme : il existe une limite à la proximité du serveur avec l’utilisateur
    L’étape suivante consiste à compiler le serveur en WebAssembly et à l’envoyer au client
    On peut alors rendre la réponse de manière optimiste pendant qu’on attend la vraie réponse du serveur
    Cela peut sembler complètement fou, mais je l’ai fait sur un vrai projet et c’était magique

    • Et pour la persistance, comment faites-vous ? À mes yeux, c’est précisément l’objectif central d’un backend
      Exécuter le serveur côté client ne résout pas cela, et au final, la latence réseau de la persistance reste la même
      L’état serveur qu’il faut réellement faire triompher au bout du compte, c’est cette persistance
    • Ça ressemble à de la surconception
      Beaucoup de surconception finit réellement par être implémentée, même sans raison particulière
    • Y a-t-il une raison de ne pas simplement utiliser un Service Worker ?
    • Peux-tu partager davantage de détails ?
    • Cela ressemble beaucoup à la prédiction côté client utilisée par les jeux multijoueurs modernes
  • J’ai créé LiveSvelte, donc s’il y a des questions, n’hésitez pas

    • Si l’on utilise LiveSvelte, y a-t-il malgré tout une raison d’utiliser des JS Hooks ?
  • Globalement, j’ai toujours voulu construire des applications selon ce modèle
    orienté événements, avec des mises à jour bidirectionnelles en temps réel entre le serveur et le client, des événements ordonnés, et des notions d’état local/distants
    Je ne connaissais pas LiveView et je n’avais jamais utilisé de langage de la famille Erlang, mais il semble clairement tenir quelque chose
    Le modèle traditionnel requête-réponse provoque souvent, de manière subtile, des problèmes de cohérence et de données obsolètes
    Si les dix dernières années ont servi à intégrer les concepts de programmation fonctionnelle dans les langages grand public, j’aimerais que les dix prochaines servent à intégrer la programmation orientée messages avec état dans le full stack grand public

    • Il existe des backends LiveView écrits en JavaScript(http://liveviewjs.com), Go(https://github.com/canopyclimate/golive), Java(https://github.com/floodfx/undead) et Python(https://github.com/ogrodnek/pyview)
      Pour information, j’ai créé ou aidé à créer les trois premiers
    • On peut installer erlang/BEAM/OTP et elixir avec asdf, et si vous avez un peu l’habitude de ce type d’outils, cela prend quelques minutes
      En suivant le guide et en expérimentant un peu, on peut lancer en environ deux heures une application de chat Phoenix basique fonctionnant dans le navigateur
    • « intégrer la programmation orientée messages avec état, ou la programmation réactive, dans le full stack grand public », c’est aussi ce qu’on appelait MVC avant que Rails ne redéfinisse le terme
  • C’est une bonne solution
    Dans mon application, j’utilise des contrôleurs Stimulus réutilisables avec LiveView, et cela fonctionne aussi de manière fluide
    Dans l’ensemble, développer avec LiveView est agréable, mais plus je l’utilise dans des scénarios réels, plus je perçois aussi les avantages des frameworks HTTP sans état comme Hotwire
    Cela semble plus performant et plus robuste aux reconnexions, et réduit aussi le besoin de déployer davantage de serveurs près des utilisateurs pour assurer la stabilité

    • Quand Stimulus/Turbo a été annoncé pour la première fois, j’espérais vraiment que cela aiderait à résoudre les problèmes décrits par l’auteur
      Mais Stimulus ne fournit pas de manière élégante de maintenir l’état côté client
      C’est du genre « l’état d’une application Stimulus existe dans les attributs du DOM », donc ce n’est pas vraiment mieux que du JavaScript vanille ou jQuery
      Je n’ai pas utilisé Stimulus dans un vrai projet, donc il est possible que les valeurs et les callbacks de changement offrent une meilleure expérience que je ne l’imaginais au départ
    • Moi aussi, j’utilise Stimulus avec LiveView
      Cette combinaison a exactement le bon niveau de complexité, et Svelte, utilisé avec LiveView, donne l’impression de gérer beaucoup de choses qui ne sont pas vraiment des problèmes au départ
      Ce qu’il faut, c’est du JavaScript vanille ou une fine couche au-dessus, pas un framework complet
      De toute façon, il n’y a pas besoin d’écrire beaucoup de JavaScript
      Le JS de mon application en production ne dépasse pas 200 lignes, et je pourrais probablement supprimer quelques contrôleurs Stimulus
      LiveView est à ce point bon
      J’ai aussi bricolé un adaptateur de hooks Stimulus-LiveView de manière très hacky, pour permettre aux contrôleurs Stimulus d’envoyer directement des événements au processus LiveView
      Et LiveView n’exige pas forcément des serveurs géographiquement distribués, à moins d’avoir vraiment trop bu le Kool-Aid façon fly.io
      Il gère aussi très bien les coupures de connexion
      Je n’ai rien eu à faire de particulier pour prendre en charge les mises à jour sans interruption
      Toute la séquence où le client perd sa connexion WebSocket, se reconnecte à la nouvelle version et restaure son état est gérée automatiquement par défaut
      Que demander de plus ?
  • Notre entreprise a tiré de gros avantages de l’usage combiné de LiveView et Alpine, en particulier parce que nous utilisons le mode CSP et ne pouvons pas autoriser eval côté client
    Quand j’ai vu LiveSvelte pour la première fois, cela paraissait très nouveau et encore peu éprouvé, avec aussi des implications non résolues dans les environnements CSP stricts
    Je suis heureux de voir que cela semble maintenant être devenu assez utile
    Notre approche pourrait en gros être appelée LiveAlpine
    Si un composant a besoin de HTML, nous utilisons un HTML Component, et s’il a un état côté serveur, nous utilisons un Live Component
    S’il faut un comportement ou un état côté client, nous définissons aussi un composant Alpine
    S’il faut recevoir des événements client côté serveur ou effectuer des requêtes HTTP, nous définissons aussi un Phoenix Hook