6 points par GN⁺ 2025-01-01 | 2 commentaires | Partager sur WhatsApp
  • Les propositions de conception système qui commencent par « let’s just » deviennent généralement bien plus complexes que prévu, et les bons choix d’architecture dépendent fortement de règles empiriques et de la compréhension du contexte
  • Les structures à plugins, l’ajout d’API et les couches d’abstraction peuvent sembler convaincants, mais doivent en réalité prendre en charge à la fois la compatibilité comportementale, la maintenance, la sécurité, les performances et les exigences de l’écosystème
  • Le traitement asynchrone, le contrôle d’accès et la synchronisation des données paraissent être des sujets familiers, mais, dans un environnement produit, ils mènent facilement à des bugs difficiles à reproduire, à une refonte du modèle de sécurité et à de grandes difficultés de synchronisation
  • Le cross-platform et les échappatoires natives (native escape) peuvent être valables pour un produit initial simple, mais lorsque les fonctions de la plateforme et l’état interne divergent, il devient difficile de préserver la qualité et la cohérence
  • Ces schémas ne sont pas toujours mauvais, mais, dans la plupart des cas, ils ne sont pas nécessaires ou il existe des alternatives ; plutôt que de choisir des approches fragiles, il faut repartir des premiers principes (first principles)

Pourquoi « let’s just » est dangereux

  • Les propositions qui suivent « let’s just » deviennent, 9 fois sur 10, beaucoup plus complexes que ce qu’on imaginait en salle de réunion
  • L’ingénierie a aussi une dimension de science sociale : ce qui fonctionne est dépendant du contexte
  • Dire qu’une approche ne fonctionne pas est souvent perçu par un ingénieur comme un défi à relever pour prouver le contraire
  • Une grande partie du management de l’ingénierie et de l’architecture logicielle repose sur une combinaison de règles empiriques (rule of thumb) issues de l’expérience et de leçons apprises dans la douleur

« Faisons simplement en sorte que ce soit extensible par plugins »

  • Quand une seule implémentation semble insuffisante, ajouter une nouvelle implémentation dans la même architecture donne l’impression qu’on pourra obtenir des améliorations ou de nouvelles fonctions sans changer les appelants de l’API
  • Mais comme « une API n’est ni un fichier d’en-tête ni une documentation, c’est son comportement réel », les plugins qui « marchent juste » sont presque inexistants
  • Dans les logiciels modernes, l’élément qui ressemble le plus à un plugin est le pilote de périphérique
    • Les pilotes du passé avaient une qualité de fonctionnement insuffisante, au point de ne plus être tolérés, ou bien les OS modernes évoluent vers la création de leurs propres pilotes
  • Pour construire une véritable architecture extensible par plugins, il faut concevoir la deuxième implémentation en même temps que l’implémentation de base ; c’est le minimum pour prouver que le modèle fonctionne au moins une fois

« Ajoutons simplement une API »

  • Une fois qu’un produit ou une entreprise connaît un certain succès, on ajoute souvent une API au nom de l’idée qu’il faut « devenir une plateforme et attirer les développeurs »
  • Le fournisseur d’API doit en permanence arbitrer entre l’ajout de fonctionnalités et la compatibilité / interopérabilité, et la liberté de faire évoluer le système se réduit fortement à cause du comportement existant et des caractéristiques de performance
  • Le simple fait d’avoir une API ne signifie pas forcément que quelqu’un voudra l’utiliser
    • Une nouvelle API apparaît souvent lorsqu’un produit souhaite une fonctionnalité sans lui donner une priorité interne suffisante
    • Le marché visé peut être petit, très verticalisé ou limité à un domaine précis, et l’on espère qu’un partenaire externe comblera le vide via l’API
    • Mais ces partenaires ont aussi leur propre activité et leurs propres clients, et ils ne souhaitent pas forcément adopter un produit supplémentaire pour résoudre le problème
  • Devenir une plateforme est une activité qui suppose une demande réelle importante ; il est rare que quelques API suffisent à créer une base économique pour des tiers

« Ajoutons une couche d’abstraction de plus »

  • La phrase de Butler Lampson, « Tous les problèmes de l’informatique peuvent être résolus par un niveau d’indirection supplémentaire », contient une part de vérité
  • Les échecs apparaissent surtout de deux manières
    • Une abstraction introduite trop tôt reste dans l’architecture comme une sur-abstraction sans plan d’usage réel
    • Une abstraction ajoutée plus tard peut rendre la maintenance, la sécurité et l’optimisation des performances extrêmement complexes
  • Windows NT contenait dès le départ beaucoup de sur-abstractions qui n’ont jamais été réellement utilisées
  • Dans l’évolution de Mac OS, certaines abstractions qui semblaient étranges au départ sont devenues utiles deux versions plus tard ; la différence tenait à l’existence d’un plan
  • Si une abstraction ajoutée après coup n’est utilisée que dans une partie du code, la quantité de code qui ne l’utilise pas augmente, et la charge de maintenance aussi

« Rendons-le asynchrone »

  • Une grande partie des 25 premières années de l’informatique a été consacrée à comprendre et à implémenter le fonctionnement asynchrone
  • Dans les cursus de troisième cycle des années 1980, on passait beaucoup de temps sur des sujets comme les philosophes qui dînent, le producteur-consommateur ou le barbier endormi
  • Aujourd’hui, beaucoup d’ingénieurs abordent les problèmes asynchrones sous une forme largement abstraite grâce aux règles des couches de données et aux frameworks web
  • Lorsqu’on gère directement l’asynchrone en dehors du framework ou de la couche de données, tout peut sembler bien fonctionner au début, puis, un an plus tard, apparaissent des bugs difficiles à reproduire
  • On ne peut alors qu’espérer qu’il ne s’agisse pas de corruption de données

« On ajoutera le contrôle d’accès plus tard »

  • L’emplacement du contrôle d’accès a longtemps relevé du débat théorique, mais les systèmes actuels évoluent dans un environnement bien plus complexe, soumis à des attaques permanentes
  • Tout le monde sait qu’il faut de la sécurité dès le départ, mais, pour aller vite sur le marché, presque aucun système ne conçoit entièrement son contrôle d’accès et son modèle de sécurité dès le début
  • Sans partir du point de vue des clients et des attaquants, il est difficile de produire un modèle de contrôle d’accès adapté au produit
  • Ajouter le contrôle d’accès après coup conduit souvent à l’échec, ou à une réécriture complète du produit plus tard
  • Et cette réécriture est une mauvaise expérience pour tout le monde, y compris les clients

« Synchronisons les données »

  • Dans un environnement avec plusieurs appareils, applications SaaS et stockages de données, la proposition « synchronisons simplement les données » revient souvent
  • Comme l’a souligné Ray Ozzie, pionnier du client/server et de la synchronisation de données, la synchronisation est un problème difficile
  • En informatique, un problème difficile est souvent un problème extrêmement délicat, avec de nombreux défis qu’on n’apprend qu’avec l’expérience
  • Même dans un stockage de données doté d’une sémantique complète et de transactions, la synchronisation est difficile ; avec des blobs, des données non structurées ou des transformations de données, la difficulté grimpe brutalement
  • Fonder une solution sur la synchronisation des données est presque toujours un choix qu’on préférerait éviter, et c’est aussi pour cela qu’il existe des entreprises valant des milliards de dollars dont toute l’activité repose sur ce sujet

« Faisons du cross-platform »

  • Le cross-platform est un débat récurrent depuis longtemps ; il y a toujours quelqu’un pour dire que son code marche très bien, ou pour citer Unity et les jeux
  • Dire qu’on va construire quelque chose en cross-platform revient en pratique presque à promettre qu’on va créer un système d’exploitation, un fournisseur cloud ou un navigateur
  • Le cross-platform fonctionne bien dans deux cas
    • Quand la plateforme est nouvelle et simple, par exemple lorsque le cloud se limite au calcul et à un stockage simple
    • Quand l’application ou le produit est nouveau et simple
  • Ces conditions cessent d’être réunies dès qu’on diverge de la plateforme sous-jacente, ou qu’on commence à développer des fonctions qui s’expriment de manière totalement différente sur chaque plateforme cible
  • Microsoft a eu de plus en plus de mal à maintenir Office pour Mac et Office pour Windows avec le même code, au point de forker le code d’Office en 1998, sans jamais revenir en arrière ensuite
  • Microsoft existait à l’origine comme entreprise de création d’applications cross-platform, mais cela fonctionnait à une époque où la documentation des API d’OS tenait sur une centaine de pages et où chaque OS dérivait de CP/M
  • Article lié : Divergent Thoughts on Cross Platform

« Prévoyons une échappatoire native si nécessaire »

  • Comme le cross-platform ne fonctionne bien que pendant une période limitée, les frameworks et les abstractions d’API fournissent souvent une échappatoire native (native escape)
  • L’idée consiste à appeler directement la plateforme native lorsqu’elle évolue plus vite que le framework et expose des fonctions que celui-ci n’a pas encore intégrées
  • Mais les frameworks ou API qui fournissent l’abstraction maintiennent aussi un état interne ou des caches
  • Appeler directement la plateforme native modifie alors des structures de données et des états que le framework ignore
  • Certains frameworks fournissent des mécanismes d’échange de données ou d’état entre le code d’échappement et le framework, mais cela ressemble davantage à une réintroduction d’architectures de type malloc/free à l’ère de la gestion automatique de la mémoire

On peut les choisir, mais ce ne sont pas des options par défaut

  • Il ne faut pas répondre « non » à toutes ces approches dans tous les cas
  • Dans certains contextes, elles peuvent fonctionner
  • Mais dans la plupart des situations, ces schémas ne sont pas nécessaires ou il existe de meilleures options
  • Au lieu de se saisir d’abord de patterns logiciels à fort risque d’échec, il faut résoudre le problème à partir des premiers principes

2 commentaires

 
ndrgrd 2025-01-02

Pour les plugins, l'essentiel est de concevoir l’interface en filtrant au maximum les comportements indispensables. Si l’on se contente de reprendre tant bien que mal la structure du code actuel pour créer l’interface, elle devient inévitablement une interface inutile liée à cette implémentation, mais ce genre de cas est vraiment fréquent…

 
GN⁺ 2025-01-01
Avis sur Hacker News
  • Le problème avec ce genre d’idées tient moins à l’idée elle-même qu’à l’approche « faisons-le, tout simplement » ou aux attentes qui l’accompagnent.
    Par exemple, si l’on considère une API comme « juste une fonctionnalité de plus » du produit, en se disant « ajoutons simplement une API », le taux de réussite sera probablement comparable à celui de « ajoutons simplement une UI ».
    Pour créer une bonne UI, il faut être prudent et rigoureux, et avoir aussi des spécialistes du domaine.
    Il n’y a aucune raison qu’une autre interface du produit soit différente : l’essentiel n’est pas tant de savoir si l’idée est bonne ou mauvaise, mais que c’est quelque chose qu’on ne doit pas faire “simplement”.

    • Dans un ancien emploi, nous avions une règle.
      Les seules personnes autorisées à dire « simplement » étaient les développeurs réellement responsables de faire fonctionner la chose ; si un autre développeur le disait, cela revenait à se porter volontaire pour s’en charger.
      Cette règle nous convenait bien.
    • Exact. Quand on ajoute une API, il n’y a pas de « simplement ».
      Pour faire correctement une API, il faut beaucoup de conception et de gestion de la complexité.
      Si elle est mal conçue, le client devra faire plusieurs appels là où un seul aurait suffi, ou bien l’API sera confuse et sera appelée de travers, voire impossible à utiliser.
      Il faut aussi de l’authentification et de l’autorisation, donc mettre en place OAuth2, ou au minimum générer, stocker et vérifier des jetons d’API de manière sûre.
      Les données doivent aussi être manipulées de façon sécurisée, et si les performances sont mauvaises, la base de données peut se retrouver écrasée par la charge.
      Ajouter du caching introduit l’invalidation du cache ainsi que la complexité des serveurs et processus nécessaires pour le prendre en charge.
      Sans limitation de débit, un client mal fichu peut marteler l’API ; avec une documentation médiocre, elle est pratiquement inutile.
      Selon les cas, il faut même fournir des SDK pour plusieurs langages, et sans bons messages d’erreur, un nouvel utilisateur ne saura pas pourquoi son appel échoue.
    • La plupart des conseils professionnels ressemblent aux conseils amoureux.
      On généralise ce qui s’est mal passé pour soi, mais à moins d’être la même personne dans une situation très similaire, cela s’applique rarement tel quel.
      Les conseils qui restent constamment justes — « réfléchissez soigneusement, essayez de faire ce qui est juste, puis revenez sur les résultats » — sont tellement généraux qu’ils deviennent presque inutiles.
      Et ce genre de phrase ne vend pas très bien des billets de blog ni des livres.
    • Le métier de presales semble exister presque entièrement à cause du mot « simplement ».
      Il faut bien s’assurer que le client ne prenne pas peur quand on commence à sortir de l’eau le reste de l’iceberg.
    • Oui. L’article aurait été bien mieux positionné comme : « ce qu’il faut réellement pour faire fonctionner “simplement” une idée de système ».
      Il ne s’agirait alors plus d’une question de possible ou d’impossible, mais des façons de réussir ou d’échouer.
      Une fois qu’on connaît les détails nécessaires, il devient aussi plus difficile de dire « simplement » sans savoir ce qu’on ignore.
      Cela dit, concernant les DSL, je suis presque 100 % d’accord.
      C’est souvent une complexification inutile qui se veut mignonne, et les personnes qualifiées pour en créer devraient être à peu près celles qui ont déjà créé un langage de programmation réussi, puis en ont publié une deuxième édition ou un second langage en intégrant leurs erreurs, tout en s’étant encore trompées sur beaucoup de choses.
  • (1) Les DSL fonctionnent parfois très bien. Voir https://www.jooq.org/
    (2) Elastic Load Balancer est une boucle de contrôle qui réagit à la charge de travail, et ce genre de technologie est déjà banalisé
    (3) Dans la plupart des secteurs, le sous-provisionnement est omniprésent. Voir https://erikbern.com/2018/03/27/waiting-time-load-factor-and... et https://www.amazon.com/Goal-Process-Ongoing-Improvement/dp/0...
    (4) La détection d’anomalies n’est pas intrinsèquement un problème de systèmes distribués comme les autres points, mais quelqu’un qui s’est déjà lourdement brûlé peut en ressentir le besoin
    C’est aussi un domaine intellectuellement difficile
    Le premier algorithme qui m’a donné l’impression d’être un peu intelligent a été https://scikit-learn.org/1.5/modules/outlier_detection.html#..., et il fonctionne parfois comme par miracle
    Quand je l’ai appliqué à du texte avec des embeddings basés sur des CNN que j’utilisais en 2018, il tombait juste, mais je n’ai eu aucune chance avec SBERT

    • J’ai écrit deux DSL, dont un avec une équipe, et je considère que les deux ont été réussis
      Ils ont résolu le problème et personne ne les a maudits
      Le facteur le plus important, je pense, est qu’ils étaient tous les deux petits
      Ils étaient très similaires et réutilisaient du code
      L’un servait à écrire des règles de validation pour d’énormes formulaires, l’autre à écrire des règles de décision en fonction des réponses aux formulaires
      Un bon DSL permet à quelqu’un qui ne pouvait pas faire quelque chose de le faire
      Un DSL créé pour gagner du temps a beaucoup moins de chances d’être utile, car il y a de fortes chances qu’il ne fasse pas vraiment gagner de temps
      Dans les deux cas, il fallait intégrer dans le programme des comportements métier complexes
      Il faut donc soit enseigner le domaine aux programmeurs, soit mettre programmeurs et experts métier ensemble, soit apprendre la programmation aux experts métier
      S’il y a beaucoup de travail, donner du pouvoir aux experts métier est séduisant
      Les programmeurs peuvent faire autre chose et la boucle de feedback se raccourcit
      Si le domaine est profond, on n’a pas forcément envie d’envoyer les programmeurs à l’école pour l’apprendre ; s’il est superficiel, quelqu’un de moins cher peut peut-être s’en charger
      Les DSL s’accompagnent d’une forte charge cognitive
      Mais si l’alternative est d’apprendre un langage de programmation complet, cela devient plus raisonnable
      Un DSL destiné à faire gagner du temps concerne des gens qui savent déjà coder et veulent écrire moins de code ; le gain est faible, donc c’est généralement peu convaincant
      Puis, quand un programmeur veut modifier quelque chose, il doit apprendre ou se remémorer tout ce DSL au lieu de lire du code intuitif
      Comme règle empirique plus simple, un DSL pour programmeurs a moins de chances d’être une bonne idée qu’un DSL pour non-programmeurs
    • jOOQ est une catastrophe et je ne le recommanderais à personne
      On écrit une requête SQL, on la teste dans un outil comme DataGrip, puis on passe des heures à trouver comment la convertir dans le DSL
      Dès qu’on utilise des fonctionnalités SQL “exotiques” comme les expressions JSON, le problème empire
      Le débogage devient un flux du type « afficher le SQL généré, le copier dans un endroit comme DataGrip, optimiser la requête, puis trouver comment la réadapter au DSL »
      C’est une perte de temps énorme
      Le principal argument de vente de jOOQ est les requêtes typées sûres, mais il a perdu de son importance quand IntelliJ a commencé à valider le SQL sous forme de chaînes dans le code par rapport aux données réelles
      Le flux consistant à éditer directement le SQL et à le tester immédiatement sur la base de données est tout simplement meilleur
      jOOQ renforce l’argument du billet original sur les DSL
    • À part des choses comme les expressions régulières, je n’ai jamais vu de bon DSL, et même là, j’ai entendu beaucoup de gens se plaindre du langage lui-même
      Parmi les exemples de DSL populaires qu’on peut considérer comme mauvais ou proches de l’échec, il y a HCL, E4X, XUL, le langage de formatage de chaînes de Common Lisp, etc.
      HCL est le langage de configuration de Terraform, et il était évident dès le départ qu’il ne traitait pas le problème très courant consistant à provisionner autant d’équipements similaires qu’il y a de variables
      Les tentatives ultérieures d’ajout de fonctionnalités ont été maladroites et n’ont pas complètement résolu le problème
      E4X était un DSL JavaScript pour travailler avec XML ; dans les cas simples, il permettait d’exprimer les manipulations XML plus brièvement, mais il pouvait très vite devenir illisible, comme un mur de ponctuation
      Comme avec LINQ de Microsoft, il ne donnait absolument aucune indication à l’auteur sur la complexité de calcul du code sous-jacent
      Au final, le code utilisant ce DSL était souvent réécrit dans un style moins concis mais plus facile à analyser
      XUL était un langage d’interface utilisateur pour les extensions du chrome du navigateur Firefox, et il convenait à l’objectif de créer des extensions Firefox
      Mais Firefox voulait aussi le vendre comme technologie de base pour des applications internes d’entreprise, et dans ce domaine il était très insuffisant
      Faire des choses simples exigeait beaucoup d’astuces et de contournements
      Le langage de formatage de chaînes de Common Lisp est similaire : correct pour de petits problèmes, mais il ne passe pas à l’échelle
      Certains problèmes de formatage exigent des solutions très étranges, ou n’ont tout simplement pas de réponse, et je déteste vraiment voir du code qui appelle récursivement format
      Globalement, le problème le plus courant de cette approche est qu’elle est bricolée et ne s’étend pas bien
      On finit vite par tomber sur des problèmes qu’on ne peut pas résoudre proprement, et les gros programmes écrits dans un DSL sont souvent un cauchemar à gérer
    • Chaque fois que je vois de la haine envers les DSL, je suis perplexe, puis je finis par comprendre que ce que les gens critiquent, ce ne sont pas les DSL en général, mais les DSL qu’il faut écrire soi-même depuis zéro
      Si l’on pose un DSL sur Lisp, on n’a qu’à écrire la logique métier, pas le langage de base
      La plupart du travail est déjà faite, et le langage est utile dès le premier jour
      En faire un DSL hébergé sur Lisp peut réellement le rendre utilisable ; je ne comprends pas pourquoi on voudrait absolument créer un nouveau langage depuis zéro pour le regarder dépérir
    • Les DSL fonctionnent bien avec un IDE capable d’autocomplétion et une boucle de feedback rapide ou immédiate
  • Tous ces éléments ont de nombreux exemples de réussite
    Il est difficile d’utiliser le mot « presque » comme échappatoire
    Ça ressemble simplement à du pessimisme et à du cynisme usé
    Je comprends ce sentiment et je l’ai moi-même éprouvé ; il arrive aussi qu’il soit difficile de faire abandonner une mauvaise idée à un ingénieur passionné
    Mais ce genre d’ambiance me semble toxique

    • On dirait juste une manière engageante, pour ainsi dire accrocheuse, de dire que « ces choses sont plus délicates qu’il n’y paraît à construire correctement ou à déployer efficacement »
    • Derrière bon nombre de ces cas de « réussite », il y a une équipe d’ingénieurs aguerris par le combat qui gère tous les échecs de l’idée
      Des boucles de contrôle qui s’emballent vers l’infini ou vers des bornes max/min, des caches qui ne récupèrent pas après des pannes distribuées, des états corrompus lors de migrations à chaud, des pics de charge qui provoquent une surcharge au pire moment, de fausses alertes de détection d’anomalies signalant les jours fériés du monde entier, ce genre de choses
      Sous toutes ces idées, il y a un enchevêtrement de complexité que presque tout le monde sous-estime
    • Je suis globalement d’accord
      C’est une liste d’idées de systèmes plus difficiles qu’on ne le pense au départ, qu’il faut aborder sérieusement plutôt que traiter à la légère
      Cela ressemble vaguement à « ça a l’air bien mais ça ne marche presque jamais », mais dans le détail c’est complètement différent
      Si on les traite comme des problèmes difficiles et qu’on investit en conséquence, obtenir quelque chose qui fonctionne correctement est un résultat tout à fait ordinaire et atteignable
      Quand c’est une fonctionnalité ajoutée après coup, ou qu’on suppose naïvement que ce sera facile, ça tourne souvent mal
    • Je ne le lis pas comme du « pessimisme et du cynisme usé »
      Je le lis comme une histoire d’ingénieurs qui se plongent dans de l’optimisation prématurée alors qu’il n’y a pas de bénéfice business
      C’est vraiment omniprésent dans le secteur : on conçoit et construit un vaisseau spatial d’auto-scaling redondant parce que c’est amusant, alors qu’on pourrait préparer une sauvegarde déployable en quelques heures et surprovisionner les serveurs de 200 % pour un coût qui serait peut-être inférieur d’un facteur dix
      Il arrive que ces idées soient justifiées, mais seulement une fois qu’elles deviennent nécessaires
      Ce n’est pas quelque chose à concevoir dès les premières phases d’un produit
      Très peu de produits ont réellement besoin de l’échelle, de la disponibilité et de la complexité que ces implémentations cherchent à gérer
    • Steven semble dire non pas que ces choses sont impossibles, mais qu’elles sont difficiles et échouent inhabituellement souvent
  • Beaucoup de gens ici semblent chercher une fonction de jugement subtile pour distinguer les exceptions, mais en réalité c’est simple
    Ces idées sont excellentes quand c’est moi qui les mets en œuvre, et elles ne fonctionnent jamais comme prévu quand c’est l’idiot qui m’a précédé qui s’en charge

    • C’est exactement ça, on dirait
      Et parfois, l’idiot qui m’a précédé, c’est moi il y a quelques mois
  • J’aimerais aussi ajouter ici le domain-driven design
    Essayer d’aligner une application sur la structure de l’entreprise tout en figeant la conception métier est une recette pour le désastre
    Dans une petite entreprise ou une entreprise stagnante, on peut ne pas voir le problème
    Mais si l’activité réussit ou grandit, on regrette très vite d’avoir essayé de créer des domaines aux noms atrocement descriptifs, déjà liés à des pratiques de travail obsolètes
    Il est bien plus flexible de concevoir autour de couches fonctionnelles, selon des méthodes éprouvées depuis des décennies, et de placer autant que possible la logique métier dans la configuration, les lignes de base de données et les workflows utilisateur

    • On finit par regretter les deux choix
      Parmi les pièges du domain-driven design, tu cites un langage obsolète et une faible réutilisabilité du code et du système pour les nouvelles tentatives ; mais à l’inverse, une conception très abstraite qui met toute la logique métier dans la configuration, les workflows, etc. n’est flexible que si toute l’organisation comprend assez bien cette abstraction, cette configuration et leurs innombrables combinaisons
      Ces combinaisons explosent rapidement en labyrinthe et produisent des comportements inconnus et inattendus dont les gens finissent par dépendre
      Les coûts d’onboarding des nouveaux développeurs et de remplacement de l’équipe de développement deviennent aussi difficiles à supporter
      L’organisation se met à parler deux langues différentes
      La plupart des demandes de fonctionnalités en apparence simples deviennent soit une énorme refonte du système si elles cassent l’abstraction, soit un « hackons simplement cette abstraction pour que cela ressemble à un changement plus sûr et plus petit pour l’instant »
      Le premier cas est toujours très difficile, même avec d’excellents ingénieurs qui comprennent parfaitement le comportement de tout le système et la base de code, ainsi que de bonnes pratiques et processus d’ingénierie ; cela peut prendre des mois ou des années
      Le second cas arrive plus souvent, et c’est ainsi que des projets « très abstraits, organisés en couches fonctionnelles, pilotés par la configuration, avec une logique métier émergente » paraissent parfaits et flexibles au début, puis finissent par devenir un « c’est quoi ce truc ? »
      Une fois le système implémenté, cette logique métier émergente devient la langue que tout le monde parle
      Quand une organisation parle deux ou trois langues totalement irréconciliables, c’est très douloureux ; et s’il n’y a pas plusieurs personnes capables de traduire couramment entre elles vers le haut, vers le bas et latéralement, on finit par se dire qu’il aurait mieux valu représenter le domaine de plus près
    • « Rendre les états impossibles impossibles à représenter » entre aussi dans cette catégorie
      Si vous concevez un système de sorte qu’un certain état soit impossible à représenter par les types, vous devez être certain que, pendant toute la durée de vie de cette conception, cet état est réellement un état impossible
  • Je ne comprends pas bien l’élément sur les boucles de contrôle qui réagissent à la charge
    C’est un composant basique et fondamental d’innombrables systèmes
    Le régulateur centrifuge des machines à vapeur des années 1800 ou des tourne-disques Victrola des années 1900 est aussi une boucle de contrôle réagissant à la charge
    Toute l’électronique est un réseau de boucles de contrôle réagissant à la charge, et il en va de même pour les transmissions automatiques des voitures

    • Le problème courant consiste à ajouter une boucle de contrôle sans comprendre suffisamment le signal, ou sans tenir compte des autres boucles de contrôle
      L’utilisation CPU est un exemple intéressant
      On peut par exemple voir un équilibreur de charge inter-région se battre avec un mécanisme de délestage interne au processus
      Parce que le signal de l’équilibreur de charge ne reflète pas le délestage, ou le reflète de manière incorrecte
      Un autre problème survient lorsqu’une boucle de contrôle qui cherche à optimiser le résultat local d’un service détériore le résultat global
      Dans l’ensemble, je pense qu’il vaut mieux placer un petit nombre de boucles de contrôle à des endroits à fort impact
    • Ce n’est pas totalement clair, mais il pourrait s’agir en particulier de la charge CPU
      La charge CPU présente plusieurs problèmes, comme l’explique https://arxiv.org/abs/2312.10172
  • Ces problèmes suivent un schéma commun
    Ce sont tous des préoccupations transversales qui ajoutent des contraintes au modèle de programmation de traitement séquentiel des données, familier aux programmeurs
    Chaque fois qu’on ajoute une contrainte, cela augmente ce à quoi tous les développeurs suivants devront continuer à penser en développant dans ce système
    Le système risque facilement de devenir trop contraint, au point de ne plus pouvoir avancer sans lever certaines contraintes
    Même si ce n’est pas impossible, cela ralentit
    Parce que les développeurs doivent à chaque fois se demander comment une nouvelle fonctionnalité interagit avec les API, la sécurité, la synchronisation, la latence, les autres plateformes et le code natif déjà promis au support
    Il est donc aussi possible de prendre en charge toutes ces propriétés
    Par exemple, si l’on fait de la synchronisation transparente des données la proposition de valeur centrale de la plateforme, tout développement ultérieur la prendra en charge en priorité et fera évoluer l’ensemble de fonctionnalités possible dans ces contraintes
    Cet ensemble de fonctionnalités ne correspondra peut-être pas exactement à ce que veulent les utilisateurs, mais c’est le périmètre qu’il prend en charge
    Le produit paraîtra attrayant aux clients qui placent cette propriété au premier rang de leur décision d’achat

  • J’ai travaillé sur des projets utilisant plusieurs DSL, un cache P2P et du parallélisme mixte, et tout fonctionnait
    C’était aussi vraiment amusant à construire
    À une exception près, c’était un bon investissement
    Le cache P2P n’était pas nécessaire, donc au final il n’a pas vraiment été rentabilisé
    Dire que ce genre de choses ne fonctionne presque jamais est donc clairement faux
    C’est complexe, mais cette complexité apporte des fonctionnalités difficiles à obtenir autrement
    La leçon tirée de l’exemple du cache P2P est qu’il faut d’abord s’assurer que cette fonctionnalité est vraiment nécessaire

  • Comme j’ai réussi à mettre en œuvre pas mal de ces idées, la lecture me paraît un peu étrange

    • Soit on sait vraiment très bien ce qu’on fait, soit on n’en a vraiment absolument aucune idée
  • « Synchronisons simplement les données » est, selon mes critères, l’une des raisons pour lesquelles les journées difficiles existent
    J’ai vu trop de systèmes ajouter des files d’attente, du traitement d’événements, etc. en pensant à des notions comme « l’échelle Internet », alors que leur portée naturelle réelle est bien en dessous de ce seuil
    Ces équipes sont naïves ou, dans le pire des cas, exploitent des dirigeants qui ne comprennent pas l’ingénierie pour obtenir de l’argent afin de s’amuser avec ce genre de problèmes

    • J’ai compris « synchronisons simplement les données » comme l’espoir naïf de lire d’un côté et d’écrire de l’autre sans que les deux sources de vérité divergent
      Pour le faire correctement, les files d’attente et le traitement d’événements sont indispensables