3 points par GN⁺ 2024-11-04 | 2 commentaires | Partager sur WhatsApp
  • Après avoir évalué plusieurs stacks pour une application de rédaction de déclarations en douane, Ruby on Rails, déjà bien maîtrisé, a été retenu pour l’implémentation initiale car il permettait concrètement de développer des fonctionnalités bien plus vite que des options plus récentes
  • La « version 2 », construite avec un backend Rust et un frontend SvelteKit, était rapide et soignée, mais ne couvrait qu’environ 10 % des fonctionnalités nécessaires, et le travail de plomberie a pris le pas sur le code métier
  • Une migration progressive obligeait à assembler soi-même le routage, l’accès aux données, les autorisations, le suivi des modifications, la recherche, les tâches en arrière-plan, le pub/sub, les e-mails, OAuth 2.0, SMTP/POP, le stockage d’objets et la génération de PDF, sans presque rien apporter en valeur utilisateur
  • Il a été décidé de rebasculer vers Rails uniquement les parties migrées vers la nouvelle stack, une décision influencée par le fait de maintenir seul l’application Rails, par le stress de ne pas répondre aux besoins des utilisateurs et par la complexité de devoir corriger plusieurs endroits à la fois
  • Après le retour à Rails, le rythme est revenu pour le développement de nouvelles fonctionnalités, l’amélioration de l’existant, les mises à jour d’interface et les corrections de bugs ; les défauts de Ruby/Rails sont gérés avec des tests, du refactoring, Turbo et du caching afin de rester concentré sur le développement produit

Point de départ : Rails comme choix provisoire

  • En 2022, au moment de commencer à développer une application de rédaction de déclarations en douane, plusieurs langages et frameworks ont été étudiés et testés en code, notamment .NET/F#, Go, Rust et React
  • Le choix final s’est porté sur Ruby on Rails
    • C’était un outil déjà maîtrisé, avec lequel il était possible d’avancer environ 10 fois plus vite qu’avec des alternatives à découvrir
  • À l’époque, l’implémentation Rails ressemblait davantage à une preuve de concept provisoire, avec l’idée de réécrire plus tard dans un autre langage, jugé moins sujet aux erreurs que Ruby
  • L’application Rails a rapidement gagné en fonctionnalités, et les collègues ont apprécié le résultat
    • Il a été possible de créer vite des fonctions qui amélioraient la productivité
    • Dès le départ, il a été possible de prévenir par le code des situations d’erreur fréquentes

Là où la « version 2 » en Rust et SvelteKit s’est bloquée

  • La « version 2 » a retenu Rust pour le backend et SvelteKit pour le frontend
  • La première version était jolie et rapide, mais ne proposait qu’environ 10 % des fonctionnalités nécessaires
  • Rust ne disposant pas d’un framework intégré comparable à Rails, il a fallu écrire davantage de code d’infrastructure et de liaison que de logique métier
  • Il est devenu clair que, pour livrer une version 2 complète, il aurait fallu stopper entièrement le développement de la version 1 ; la version 2 a donc finalement été abandonnée
  • Cela a confirmé qu’une réécriture pouvait prendre un temps comparable à celui nécessaire pour créer l’application initiale

La complexité opérationnelle créée par la migration progressive

  • L’envie d’intégrer Rust à l’application est restée présente en raison de son typage fort, de ses performances élevées et du niveau de confiance qu’apporte une compilation réussie
  • Malgré plus de quatre ans d’usage de Ruby, des problèmes d’exécution continuaient aussi à survenir
    • Il s’agissait surtout de valeurs null et d’exceptions non gérées
    • Après les déploiements, les problèmes en production étaient rapidement corrigés à partir des outils de reporting d’erreurs
  • Côté frontend Rails, le fait que la logique et le markup soient dispersés dans plusieurs fichiers était source d’insatisfaction, alors que Svelte facilitait le regroupement des éléments liés dans un seul fichier
  • Un plan a donc été établi : réécrire progressivement le nouveau frontend en SvelteKit et le nouveau backend en Rust, remplacer peu à peu les parties Rails existantes, puis supprimer Rails au terme du processus
  • Au début, la migration des pages « index » avec listes d’enregistrements et filtres a avancé rapidement vers la nouvelle stack
    • La nouvelle stack était rapide, et la partie Rust rencontrait très peu de problèmes à l’exécution
    • Les règles de déploiement déterminant quelles routes devaient passer par Rails, Rust ou SvelteKit sont devenues complexes
    • Cette complexité a été acceptée comme un état transitoire jusqu’à la bascule complète

Un travail technique devenu plus important que la valeur utilisateur

  • Avec le temps, de nouvelles fonctionnalités utiles continuaient d’être ajoutées côté Rails, et les fonctionnalités existantes devenaient plus riches et plus sophistiquées
  • Plusieurs refactorings ont été effectués pour corriger des hypothèses initiales erronées, avec l’idée qu’un schéma de base de données bien conçu profite à toutes les versions
  • L’interface Rails étant vue comme bientôt remplacée, il a été décidé de ne plus y consacrer trop de temps
  • Quelques mois plus tard, l’activité ayant suffisamment réussi, il a été possible d’embaucher un développeur à temps plein, ce qui laissait espérer une accélération de la transition vers Rust
  • En pratique, beaucoup de temps a été consacré dans la nouvelle stack à écrire des abstractions et des mécanismes
    • accès à la base de données
    • gestion des autorisations pour que les utilisateurs ne voient que les données auxquelles ils ont droit
    • suivi de toutes les modifications
    • recherche et filtres
    • application de contraintes via le système de types
  • La liste des fonctionnalités nécessaires a ensuite continué de s’allonger
    • tâches en arrière-plan
    • système de pub/sub pour les mises à jour côté client
    • fonctions d’e-mail
    • OAuth 2.0 pour la connexion à des services externes
    • SMTP et POP
    • stockage d’objets
    • génération de PDF
  • Les bibliothèques Rust étaient suffisamment nombreuses, mais le travail consistant à choisir les bonnes et à tout raccorder a été important
  • Les discussions se sont multipliées sur des détails d’implémentation technique, comme le choix de l’ORM Rust ou le calendrier de sortie et les améliorations de Svelte 5
  • Après environ un an passé à développer en Rust et Svelte, il est devenu évident que les utilisateurs ne tiraient presque aucun bénéfice de ce travail
    • Certaines pages de la nouvelle stack étaient fluides et rapides, mais ce n’étaient pas celles qui posaient problème à l’origine
    • Les pages les plus utilisées fonctionnaient toujours sous Rails et proposaient 10 fois plus de fonctionnalités que la « bêta » de la nouvelle stack
    • Des journées, voire des semaines, étaient consacrées à un travail n’ajoutant aucune valeur directe

La décision de revenir à Rails

  • Il a été décidé de réécrire en Rails uniquement les parties déjà en production sur la nouvelle stack
  • Il ne s’agissait pas de réécrire toute l’application, mais de rebasculer vers Rails les portions migrées en Rust/SvelteKit
  • La décision a été difficile, mais rationnelle
    • Beaucoup de temps et de code avaient déjà été investis
    • Il était possible que les membres de l’équipe n’apprécient ni Ruby ni Rails
    • Heureusement, l’équipe a compris la décision et s’est montrée ouverte à l’apprentissage
  • Les points forts de Rails tiennent au grand nombre de fonctionnalités incluses par défaut, à un écosystème de bibliothèques mature et stable, et à des conventions ainsi qu’à une conception fortement orientée qui permettent de garder un code concis
  • Rails aide à rester concentré sur la création du produit et réduit la charge liée à l’écriture de code de support de bas niveau

Enseignements après le retour à Rails

  • L’essai avec Rust et Svelte n’a pas été une perte totale
    • L’apprentissage de nouveaux langages et frameworks a apporté des idées et des intuitions utiles dans d’autres contextes
    • Développer une application web est une suite de choix et de compromis
    • Il faut soit accepter les limites d’un framework, soit investir dans sa propre implémentation, en évaluant si cet investissement procurera un avantage concurrentiel et un bénéfice à long terme
  • Le retour vers Rails a été en grande partie simple, et il a aussi réduit le stress
  • Ces dernières semaines, la productivité est revenue dans le développement de nouvelles fonctionnalités, l’amélioration de l’existant, les mises à jour d’interface et la correction de bugs
  • Les défauts de Ruby et de Rails sont désormais considérés comme des contraintes à intégrer au moment d’écrire le code
    • S’il y a beaucoup de problèmes à l’exécution, il faut davantage tester
    • Un code spaghetti difficile à maintenir est plus souvent le fait des développeurs que du langage ou du framework
    • Il faut consacrer plus de temps au refactoring et à l’organisation du code
    • Si Rails est difficile à faire évoluer, il est probable que d’autres solutions le soient aussi
    • Rails est suffisamment rapide, et Turbo ainsi que le caching offrent des moyens de contourner ses limites
  • Du point de vue des utilisateurs, la stack Rust n’était pas sensiblement plus rapide
  • Sur Rails, la durée P95 de la page la plus lourde est de 338 ms, ce qui laisse une marge d’amélioration mais reste largement assez rapide dans l’usage
  • Il n’existe pas de langage ou de framework parfait ; il faut connaître leurs forces et leurs faiblesses, puis savoir les gérer
  • Rails fait partie des très bons frameworks pour qui veut se concentrer sur la création d’un bon produit, et d’autres frameworks pérennes avec une communauté active peuvent être tout aussi bons

2 commentaires

 
lemonmint 2024-11-04

Réécrivez-le en Ruby
Réécrivez-le en Rails

 
GN⁺ 2024-11-04
Avis sur Hacker News
  • Je pense que Rails a une très grande avance sur les autres stacks pour créer des applications web, y compris Django ou Laravel
    Il a pris en charge toutes les parties ennuyeuses, connaît les besoins nécessaires, et gêne moins quand on construit une vraie application. En 15 ans de développement d’applications web, j’ai utilisé Meteor, Remix, Next.js, Node.js basé sur Express, etc., mais j’ai l’impression que le développement web est déjà un problème largement résolu. Côté JavaScript, poussé par l’argent des grandes entreprises, on dirait surtout que les développeurs jouent avec de nouveaux jouets; Rust et Go sont excellents pour le développement système et l’infrastructure de déploiement, mais les forcer dans le développement web n’a, selon moi, aucun sens

    • Même si ce n’est pas une stack à la mode, j’ai l’impression que Spring Framework/Spring Boot est globalement la meilleure stack pour applications web
      Elle s’intègre facilement avec d’innombrables bibliothèques Java, et le typage statique aide dans de nombreuses situations. Rien que le data binding conventionnel via Jackson était déjà excellent depuis longtemps; dans les langages à typage dynamique, ce genre de choses donne davantage l’impression d’avoir été ajouté après coup
    • Ces frameworks ressemblent à une voie rapide pour lancer un projet, parce qu’il n’y a pas de grandes décisions à prendre
      Mais après être allé en profondeur dans Rails, Django ou Laravel, si l’on doit faire quelque chose qui sort des conventions, cela peut devenir compliqué. Comme on n’a pas écrit soi-même le code de liaison, il se crée souvent un manque de compréhension plutôt qu’une barrière technique. Malgré tout, si l’on apprend correctement les entrailles du framework, le simple fait de lire le code peut faire économiser énormément de temps de développement. Bien sûr, en pratique on ne le fait pas, et comme tout réécrire est beaucoup trop amusant, on finit par apprécier de nouvelles tentatives même quand elles n’ont aucun sens sur le plan business
    • Je ne suis pas d’accord. Rails est excellent en fonctionnalités et en productivité, mais ce n’est pas une solution universelle
      Ne vous fiez pas seulement à mon avis, regardez les données: https://www.youtube.com/watch?v=Qp9SOOtgmS4
      Si vous utilisez Rails pour un service dont vous ne connaissez pas précisément le nombre d’utilisateurs ou de requêtes par seconde, vous pouvez économiser sur le coût de lancement, mais finir par dépenser davantage en coûts serveur
    • Ayant utilisé AOLServer et ayant travaillé en 1999 dans une startup qui construisait quelque chose de proche de Rails en Tcl, je ne suis pas vraiment d’accord
      La démo de Rails ne m’a pas particulièrement séduit, si ce n’est qu’elle a montré à quel point la chance compte pour l’adoption et l’attention. Même aujourd’hui, je vois mal sa valeur, et je choisirais Spring ou ASP.NET. Les fondateurs de cette startup basée sur Tcl ont ensuite créé OutSystems, l’un des rares outils RAD à avoir réussi dans le développement web à l’échelle entreprise, et l’un des succès de l’industrie IT portugaise
    • La plupart de ces remarques s’appliquent aussi à Django
      Je préférais Rails autrefois, mais avec la forte croissance de Python ces dix dernières années et plus, Django est devenu un choix plus pragmatique. Les développeurs en machine learning et en data science connaissent déjà Python, et la documentation de Django est tellement bonne qu’ils peuvent devenir productifs en très peu de temps si nécessaire. Je l’ai vu directement sur plusieurs projets
      Django réduit aussi les décisions et débats autour de la structure d’application par rapport à des bibliothèques moins prescriptives ou des microframeworks. La communauté Django/FLOSS est aussi bien plus active que je ne l’imaginais, et les interactions y ont été agréables. Cela dit, j’aimerais qu’il y ait des générateurs comme dans Rails et du seeding de données intégré, par exemple des fonctionnalités comme rake db:seed
  • J’utilise Rails depuis 17 ans, je l’aime toujours, et je le préfère aussi pour le frontend
    Il offre toutes les options pour séparer le code sans transformer le haut des fichiers en une liste inutilement longue d’includes, comme on le voit dans les applications Angular. Je ne vois pas d’inconvénient à séparer la logique et le balisage côté frontend. On peut tester la logique indépendamment, et lorsqu’on cherche un bug, on sait généralement s’il vient du balisage ou de la logique, ce qui facilite le suivi. J’ai aussi écrit pas mal de méthodes Ruby de plus de 200 lignes, mais c’était vraiment de ma faute, et un système de tests unitaires plus fin permet d’éviter cela

    • Une autre façon d’éviter les longues listes d’includes est de tout rendre global
      Je ne sais pas trop si c’est un avantage. Les imports peuvent prendre beaucoup de place, mais ils montrent explicitement comment tout est relié. Si cela gêne, on peut les replier dans l’IDE
  • J’aime ce billet parce qu’il est réaliste. La phrase clé mérite d’être gardée en permanence à son chevet
    « Fait intéressant, les choses qui m’agaçaient autrefois dans Ruby et Rails me dérangent désormais beaucoup moins. J’ai accepté qu’il n’existe pas de langage ni de framework parfait. Il suffit d’en connaître les forces et les faiblesses et de composer avec elles »

    • J’aime le côté pragmatique du billet. On dirait une bonne introduction à lire avant de réécrire quelque chose
    • J’ai souvent l’impression que les gens qui se plaignent des frameworks ont une vision du monde parfaite avec laquelle ils ne veulent pas transiger
      Dans beaucoup de cas, ils ne comprennent pas assez le framework et ne savent pas pourquoi les choses sont ainsi. Mais connaître ses limites et travailler avec le framework est bien plus efficace. Il faut consacrer du temps à bien comprendre les outils que l’on utilise
    • Cette phrase vient dans le contexte de cette tentative
      « Entre-temps, j’ai commencé à créer la ‘version 2’ de l’application. J’ai choisi Rust pour le langage backend et SvelteKit pour le frontend. »
      Comme la v1 a commencé avec Rails, je lis cela comme un billet qui invite à la prudence lorsqu’on abandonne un framework qui fonctionne déjà bien
    • Pour moi aussi, c’est ce que j’ai compris de plus important. Je suis beaucoup plus heureux maintenant que je ne passe plus mon temps à penser: « Si seulement il y avait les énumérations de Rust! »
  • Rust est un langage créé par des gens très intelligents, mais son centre d’attention semble davantage porter sur la théorie des types et l’économie de quelques allocations que sur la possibilité, pour un développeur de terrain comme moi, de construire quelque chose d’utile et de cohérent
    J’utilise Rust depuis 2020, et pourtant, quand je lis des articles du blog Rust, j’en comprends littéralement à peine la moitié

    • Peux-tu donner des exemples de ce qui te paraît incohérent dans Rust ? Au contraire, je le perçois comme un petit langage bien conçu, très cohérent
      C’est particulièrement vrai par comparaison avec les grands langages mainstream. Par exemple, les traits couvrent à la fois les cas d’usage des classes abstraites et des concepts en C++, ainsi que des classes abstraites et des protocoles en Python. Il n’y a pas non plus d’incohérence entre utiliser des exceptions ou retourner des valeurs pour gérer les erreurs. Il y a bien les panics, mais ils s’utilisent comme des assertions. Si if-else est une expression, il n’y a pas besoin non plus d’un opérateur ternaire séparé
    • Rust est un langage système, et il est excellent dans ce domaine. Si on le compare à ceux de sa catégorie, les articles de blog sur C++ paraissent bien moins cohérents
      Il y a récemment une tendance à vouloir utiliser Rust pour tout, mais ce n’est pas un langage conçu pour des applis CRUD. Cet article ressemble au fond plutôt à une étude de cas sur le thème : « utilise l’outil adapté au travail. Le langage que tu aimes sur ton temps libre, ou le langage à la mode, n’est pas forcément le bon »
    • Rust est essentiellement un remplaçant de C++
      Si tu peux te permettre un ramasse-miettes, tu n’as pas besoin d’utiliser Rust ou C++ ni de te soucier de la gestion mémoire. Certains présentent Rust comme un langage de programmation généraliste, et en théorie c’est vrai, mais C++ était aussi présenté ainsi dans les années 90. Minimiser les allocations mémoire est généralement précisément la caractéristique que l’on recherche quand on choisit Rust ou C++
  • Il est difficile d’écrire rapidement une grosse application web en Rust
    Une grosse application écrite avec Rails peut ne pas tourner vite, contenir beaucoup de bugs, ou être difficile à maintenir et à faire évoluer. Des choix comme Java, C# ou Go peuvent sembler moins sexy ou moins cool, mais ils peuvent permettre de livrer presque aussi vite qu’avec Rails tout en s’exécutant à des vitesses proches de Rust. En général, cela donne aussi des projets avec moins de bugs, plus faciles à maintenir et à faire évoluer

    • On ne peut pas sérieusement dire qu’un langage système bas niveau comme Go est aussi productif que Rails, un framework haut niveau pour applications CRUD
      Peu importe à quel point on déteste Rails, cela revient à peu près à dire qu’on peut créer un blog plus vite en C++ qu’avec WordPress
    • Dire qu’« une grosse application écrite avec Rails n’est pas rapide, contient beaucoup de bugs et est difficile à maintenir et à faire évoluer » me paraît être une généralisation excessive
      Ce n’est pas forcément le cas si elle est construite avec soin. J’ai vu beaucoup d’apps Rails volumineuses, avec très peu de bugs, stables et faciles à modifier, et j’ai aussi vu des apps Rails et Go catastrophiques. Certains langages ou frameworks peuvent rendre plus facile de tomber dans cet état, mais tout reste possible, et les compromis rendent les choses difficiles pour d’autres raisons. Avec de la discipline, on peut faire fonctionner n’importe quoi
    • On peut aussi créer avec Rails de grandes applications rapides, avec peu de bugs, et qui ne sont pas difficiles à maintenir ni à faire évoluer. Il existe beaucoup de cas réels
      À niveau de développeurs comparable, Rails permet de développer plus vite que Java, C# ou Go pour la plupart des fonctionnalités d’applications web. D’après mon expérience, jusqu’à trois fois plus vite. J’ai travaillé à la fois sur de gros monolithes et sur des architectures orientées services, et j’ai aussi collaboré avec des équipes Java. À une époque, avec cette même conviction, j’avais même introduit Go dans une organisation Rails
      Au final, le vrai problème était que MVC ne convient pas à tout, et que les namespaces n’étaient pas utilisés de façon assez stricte. En corrigeant cela dans des zones petites et ciblées, Rails reste tout à fait correct
    • Je n’ai jamais utilisé Basecamp, mais je pense que le produit est bien écrit et correct
      Donc, avec suffisamment d’encadrement, une bonne architecture et de la maintenance, je pense que c’est aussi possible avec Rails
  • J’ai récemment commencé à tester AdonisJS comme alternative TypeScript à Rails
    Si « Rails en TypeScript » t’intéresse, je recommande d’y jeter un œil. Il ressemble beaucoup plus à Rails ou Laravel que les stacks TypeScript les plus populaires, et il adopte une approche batteries incluses au lieu de te laisser choisir chaque partie de la stack toi-même ou faire confiance à des templates tiers

    • AdonisJS m’intriguait, et ce commentaire me donne envie de l’essayer
      Ces derniers temps, je suis attiré par les frameworks backend batteries incluses comme Rails, Laravel ou Django, mais comme j’ai utilisé presque exclusivement TypeScript pendant toute ma carrière, il est plus simple de continuer ainsi que de changer maintenant. Je serais curieux de connaître ton retour après test, et de savoir si tu peux le comparer aux autres frameworks mentionnés
    • J’avais envie d’essayer AdonisJS, donc c’est une bonne nouvelle
      Pour un projet perso récent, j’ai choisi NestJS, mais j’ai découvert Adonis peu après, et je me demande sérieusement si je ne vais pas migrer
  • Les technologies comme Next.js et SvelteKit sont populaires parmi les développeurs JavaScript parce qu’elles atténuent le problème de la mauvaise expérience de développement backend avec Node.js
    Faire un backend en TypeScript ressemble à le faire en C#, mais avec l’impression qu’il manque les avantages d’un langage correctement conçu. L’expérience est très différente de celle consistant à construire un backend avec Rails. Les développeurs Node.js commencent eux aussi à comprendre que le problème ne se limite pas à l’écosystème et aux outils : les frameworks qui fournissent une solution globale pour construire des applications comptent. C’est précisément là que Next.js et SvelteKit aident, et c’est aussi là que Rails avait innové en 2006

    • J’aime TypeScript. Je serais curieux de savoir en quoi, comparé à C#, ce ne serait pas un langage correctement conçu
    • Comparer Next.js ou Remix à Rails, Django ou Laravel, c’est forcé
      On compare le simple fait de pouvoir exécuter du code côté backend avec Rails ? Où sont l’accès à la base de données, les migrations, l’ORM, les files de jobs, les tâches planifiées, la validation, la traduction, l’authentification et la prise en charge de l’autorisation ? La seule chose à laquelle Next.js aide, c’est à pousser les gens vers la plateforme Vercel
    • Si je devais choisir entre C# et TypeScript, je choisirais volontiers C# pour le backend
      Pour le frontend, je préfère TypeScript à JavaScript
  • Les commentaires disant que Rust n’est pas terrible pour les backends web me laissent un peu perplexe
    En construisant surtout de petits services comme beampaint.com ou probablyup.net, j’ai eu l’expérience inverse. Avec une application plus grosse, la complexité pourrait fortement augmenter — et c’est sans doute ce qui arriverait —, mais pour donner la confiance nécessaire dans une grande base de code, Rust est excellent

    • Est-ce que la difficulté ne grimperait pas brutalement dès qu’on a besoin de davantage de fonctionnalités relevant du framework ?
      Les vieux frameworks ont ce genre de choses par défaut, mais les frameworks Rust sont moins susceptibles de les avoir, en raison de leur jeunesse. Il suffit d’imaginer que les fonctionnalités manquantes passent de deux à six
  • Cet article ressemble presque à l’histoire de ma vie
    Après avoir utilisé Rails, j’ai lancé en 2013 une application SaaS écrite en Go, et j’ai dû tout comprendre par moi-même. Migrations, couche base de données, asset pipeline, déploiement, validation, logging, paiements, etc. : il y avait énormément de choses que Rails fournit tout simplement

    • Mais cette expérience t’a très probablement rendu meilleur développeur
    • On compare un langage de programmation bas niveau, orienté système et réduit à l’ossature, avec un framework de très haut niveau au-dessus d’un langage de très haut niveau
      Je n’aime pas particulièrement Go, mais ici, ce n’est pas Go qu’il faut blâmer. Utiliser Go pour une application CRUD était une décision épouvantable dès le départ
  • J’ai un sentiment similaire avec Django
    Les problèmes de performance venaient bien plus souvent des requêtes de base de données que de Django lui-même

    • Presque toujours, ce sont les requêtes de base de données qui prendront le plus de temps, mais j’ai vu trop d’ingénieurs ne même pas appliquer des optimisations de base comme créer des index
      Parmi les optimisations simples souvent oubliées : créer des index en base de données, déléguer davantage de logique à la base plutôt qu’au code — par exemple avec des pipelines MongoDB ou des index partiels Postgres —, activer la compression Brotli/zstd pour la plupart des requêtes, mettre en cache des objets ou des requêtes avec un cache en mémoire comme Redis, et définir des en-têtes de contrôle du cache appropriés. Côté frontend, il faut aussi des optimisations comme éviter de rendre des milliers d’objets en nœuds DOM et utiliser plutôt canvas. J’ai vu ce problème récemment dans une application de cartographie