2 points par GN⁺ 2023-10-31 | 1 commentaires | Partager sur WhatsApp
  • La plus grande leçon qui revient après une longue expérience du développement, c’est que la complexité est l’« ennemi éternel » d’une base de code, et qu’elle crée un état où un petit changement casse des endroits inattendus
  • L’outil le plus puissant pour réduire la complexité est de dire « non » aux fonctionnalités et aux abstractions, mais quand un compromis réaliste est nécessaire, une solution 80/20 permet de livrer l’essentiel de la valeur avec peu de code
  • La conception et les tests mettent davantage l’accent sur la recherche de bonnes frontières une fois que la forme du système apparaît, plutôt que sur une abstraction trop précoce, et privilégient les tests d’intégration qui tiennent dans la durée plutôt que les tests unitaires
  • Les outils, les systèmes de types, la journalisation, les débogueurs et la conception d’API doivent réduire la charge cognitive des développeurs, et la grande valeur pratique d’un système de types réside dans l’autocomplétion de l’IDE
  • Même des techniques bien nommées comme DRY, la séparation des préoccupations, les microservices, les SPA, les génériques ou le refactoring excessif peuvent devenir des vecteurs de complexité si elles rendent le code plus difficile à comprendre et à maintenir

La complexité est le risque numéro un d’une base de code

  • La complexité transforme soudain un système auparavant compréhensible en quelque chose de difficile à manipuler, et un changement à un endroit casse ailleurs, dans des zones qui semblent sans rapport
  • La complexité peut entrer par l’intermédiaire de développeurs ou de chefs de projet pleins de bonnes intentions, et il arrive que la complexité qu’on a soi-même introduite soit la source du problème
  • Il n’existe pas de « massue » universelle pour résoudre la complexité ; la meilleure réponse est de ne pas la laisser entrer dès le départ

« non » et « ok » : refus et compromis réaliste

  • La meilleure arme contre la complexité, c’est « non »
    • « Cette fonctionnalité, on ne la développe pas »
    • « Cette abstraction, on ne la crée pas »
  • Mais même si « non » est un bon conseil d’ingénierie, cela peut être moins favorable aux récompenses ou aux promotions
  • Lorsqu’il faut faire un compromis réaliste, on répond « ok », puis on cherche une solution 80/20
    • Une manière d’implémenter 80 % de la valeur voulue avec 20 % du code
    • Elle peut ne pas avoir toutes les finitions et être un peu moins élégante, mais elle délivre l’essentiel de la valeur tout en gardant une faible complexité
  • Comme un chef de projet peut oublier des exigences de détail, les déplacer ou quitter l’entreprise, l’approche 80/20 peut parfois être un meilleur choix

La conception et la décomposition du code sont risquées si elles arrivent trop tôt

  • Au début d’un projet, la forme du système est encore floue, comme de « l’eau », donc on évite la décomposition trop précoce
  • Avec le temps, de bonnes frontières apparaissent
    • l’interface avec le reste du système est étroite
    • la complexité interne est masquée par un petit nombre de fonctions ou d’abstractions
  • Si l’on crée des abstractions trop tôt, il est facile de produire de mauvaises abstractions ; mieux vaut donc attendre
  • Pour les développeurs qui veulent construire de grosses abstractions dès le départ, il peut être utile de leur donner des livrables jetables comme des UML, ou d’exiger une démo fonctionnelle pour le lendemain
  • Un prototype initial montre plus vite du code qui fonctionne réellement et des contraintes réalistes

Les tests : pas « tout à la fin », mais en parallèle quand la forme se précise

  • Les tests évitent beaucoup de problèmes, mais l’auteur est opposé à l’idée d’imposer le test first avant même de comprendre le domaine
  • Il préfère écrire l’essentiel des tests après le prototype, quand le code commence à se solidifier
  • L’attitude qui consiste à sauter les tests sous prétexte que « ça marche sur ma machine » est très mauvaise
  • Les préférences selon le type de test sont nettes
    • tests unitaires : utiles au début d’un projet, mais ils cassent facilement quand l’implémentation change et peuvent compliquer le refactoring
    • end to end : ils montrent le comportement du système complet, mais lorsqu’ils échouent il est difficile d’en comprendre la cause, et s’ils cassent souvent ils finissent facilement ignorés
    • tests d’intégration : assez haut niveau pour vérifier la justesse du système, assez bas niveau pour trouver la cause avec un débogueur ; ils sont proches du meilleur compromis
  • Une fois les API de frontière stabilisées, il faut investir fortement dans les tests d’intégration autour d’elles
  • Les tests end-to-end doivent rester un petit ensemble bien maintenu, centré sur les fonctionnalités UI les plus courantes et quelques edge cases importants
  • Le mocking n’est utilisé qu’en cas de nécessité, si possible seulement à l’échelle de grandes frontières
  • Lorsqu’un bug est découvert, l’exception consiste à d’abord le reproduire avec un test de régression, puis à le corriger

Agile, refactoring et Chesterton's Fence

  • Agile n’est pas la pire chose en soi et peut servir comme mode d’organisation du développement, mais il faut se méfier des « agile shamans » qui s’en servent comme d’un outil d’exonération en cas d’échec
  • Les prototypes, de bons outils et le recrutement de bons développeurs comptent davantage dans le succès d’un logiciel, et aucun processus n’est une silver bullet capable de tout résoudre
  • Le refactoring est utile, surtout plus tard quand le code s’est durci, mais plus un refactoring est important, plus il risque d’échouer
    • on le découpe en petites étapes
    • on maintient autant que possible le système dans un état qui continue de fonctionner
    • on ne passe à l’étape suivante qu’une fois la précédente terminée
  • Une abstraction excessive peut mener à l’échec du refactoring, voire du système
    • J2EE est cité comme un cas ayant nui à beaucoup de projets
    • OSGi a voulu enfermer la complexité et l’a finalement renforcée, au prix de plusieurs années-homme de reprise
  • Chesterton's Fence rejoint l’idée qu’il ne faut pas supprimer un code peu esthétique avant d’avoir compris pourquoi il existe
  • Un code en production, même imparfait, mérite du respect, et plus le système est grand, plus il faut d’abord du temps pour le comprendre

Microservices et outils

  • Les microservices ajoutent des appels réseau à un problème déjà difficile : découper correctement un système
  • Les outils peuvent fortement améliorer la productivité et la compréhension des développeurs
    • dans un nouvel environnement, il vaut la peine d’investir du temps pour apprendre les outils
    • deux semaines passées à maîtriser les outils peuvent doubler la vitesse de développement
    • sans documentation, il faut aller demander à d’autres développeurs et creuser soi-même
  • La complétion de code de l’IDE évite d’avoir à mémoriser toute une API et est presque indispensable en développement Java
  • Un bon débogueur est extrêmement important
    • points d’arrêt conditionnels
    • évaluation d’expressions
    • exploration de la pile
  • Un nouveau développeur devrait apprendre en profondeur le débogueur disponible ; cela peut lui en apprendre davantage sur l’ordinateur qu’un cours universitaire

Systèmes de types, expressions et DRY

  • La plus grande valeur d’un système de types réside dans le support outillé qui affiche les actions possibles quand on tape un point
  • La sûreté des types est utile aussi, mais la complétion et la navigation dans le code ont une valeur pratique encore plus grande
  • Il faut se méfier des développeurs qui utilisent le système de types de manière trop abstraite
    • les génériques peuvent être particulièrement dangereux
    • dans la plupart des cas, il préfère les limiter à des classes conteneurs
  • Plutôt que d’entasser de courtes conditions sur une seule ligne, mieux vaut les décomposer en variables intermédiaires avec des noms explicites : c’est meilleur pour le débogage et la compréhension
  • DRY est un bon conseil, mais il faut de l’équilibre
    • un code dupliqué simple et clair vaut parfois mieux qu’un modèle complexe de callbacks, closures ou objets
    • si l’élimination de la duplication augmente elle-même la complexité, le coût peut dépasser le bénéfice

Séparation des préoccupations, closures et journalisation

  • La séparation des préoccupations est une idée puissante, mais en pratique elle peut faire perdre du temps en obligeant à naviguer entre plusieurs fichiers pour comprendre un comportement
  • Comme alternative, l’auteur préfère la locality of behavior
    • en plaçant le code près de « la chose qui agit », on voit immédiatement ce qu’il fait en regardant l’élément concerné
  • Les closures conviennent bien pour abstraire des opérations sur des collections, mais en petites quantités, comme du sel
  • Le « callback hell » de JavaScript est un exemple de complexité créée par un usage excessif des closures
  • La journalisation est très importante, surtout en environnement de déploiement cloud
    • on ajoute des logs à chaque branche logique importante
    • pour les requêtes qui traversent plusieurs machines, on inclut un request ID pour regrouper les logs
    • si possible, on ajuste dynamiquement les niveaux de log
    • si possible, on ajuste les niveaux de log par utilisateur pour déboguer les problèmes d’un utilisateur précis
  • Les bibliothèques de logging peuvent être complexes, mais investir dans une bonne infrastructure de journalisation rapporte beaucoup plus tard

Concurrence, optimisation et API

  • La concurrence est un domaine dont il faut se méfier, et l’auteur préfère des modèles aussi simples que possible
    • des handlers de requêtes web sans état
    • des files de travaux distants qui ne dépendent pas les unes des autres
    • des API simples
  • Sur le web, l’optimistic concurrency peut très bien convenir
  • Même les structures de données concurrentes comme ConcurrentHashMap en Java doivent être utilisées avec prudence
  • L’optimisation ne devrait commencer qu’après identification d’un problème concret à l’aide d’un vrai profil de performance
    • il ne faut pas regarder uniquement le CPU
    • un accès réseau équivaut à beaucoup de cycles CPU, donc il faut le réduire si possible
    • voir des boucles imbriquées et se lancer immédiatement dans l’élimination d’un O(n^2) peut accroître la complexité
  • Une bonne API doit éviter de faire trop réfléchir les développeurs
    • si l’auteur d’une API reste enfermé dans une vision d’implémentation ou de domaine, elle devient difficile à utiliser
    • pour les cas simples, il vaut mieux fournir une API simple et, pour les cas complexes, une autre API plus complexe : cette stratification fonctionne bien
    • dans une approche orientée objet, le comportement devrait autant que possible se trouver sur l’objet concerné
  • L’exemple des stream/collector en Java est critiqué comme une API qui détourne inutilement des tâches courantes

Parsing, Visitor Pattern et frontend

  • Les parseurs en recursive descent sont jugés amusants et élégants
  • Les générateurs de parseurs rendent le code produit difficile à comprendre et à déboguer, tout en masquant la nature récursive de la grammaire
  • En pratique, la plupart des parseurs de production sont en recursive descent, et l’auteur recommande Crafting Interpreters
  • Le Visitor pattern est résumé très brièvement comme « mauvais »
  • Séparer frontend et backend, puis les relier via HTTP avec une bibliothèque SPA et une API JSON GraphQL revient presque à construire deux nids de complexité
  • Il faut se méfier de la tendance à utiliser de grosses bibliothèques frontend même pour de simples sites web ou des formulaires envoyés en base de données
  • Pour réduire la complexité, l’auteur a créé htmx et hyperscript
    • conserver un HTML simple
    • éviter beaucoup de JavaScript
  • React est peut-être meilleur pour l’emploi et pour certains types d’applications, mais il est vu comme un choix qui fait entrer dans la voie de la complexité frontend

Modes, FOLD et impostor syndrome

  • Le développement suit beaucoup de modes, particulièrement visibles côté frontend
  • Il faut se montrer sceptique face aux nouvelles approches présentées comme révolutionnaires
    • en informatique, beaucoup d’idées ont déjà été essayées au moins une fois
    • de mauvaises idées peuvent revenir sous un nouveau nom
  • Il est bon que des développeurs senior disent publiquement : « c’est trop complexe, c’est difficile à comprendre »
  • FOLD signifie Fear Of Looking Dumb, c’est-à-dire le fait de ne pas oser reconnaître la complexité par peur d’avoir l’air idiot
    • si un senior dit qu’une chose est complexe, un junior aura plus de facilité à admettre qu’il ne la comprend pas non plus
    • FOLD est l’une des principales sources de pouvoir de la complexité, surtout chez les jeunes développeurs
  • Les développeurs oscillent entre l’impression de tout maîtriser et celle de ne rien comprendre, et l’impostor syndrome est fréquent
  • Si tout le monde se sent imposteur, alors personne ne l’est vraiment, et un jeune développeur peut poursuivre sa carrière malgré la frustration et l’inquiétude

Lectures recommandées et conclusion

1 commentaires

 
GN⁺ 2023-10-31
Avis sur Hacker News
  • Il est étrange de voir des gens intelligents attirés par la complexité comme des papillons par la flamme
    Il faut des années pour apprendre à combattre l’envie de surconcevoir
    Une fois qu’on commence à la voir, elle devient difficile à ignorer, et désormais je peux dire immédiatement si du code est surconçu
    Malheureusement, environ 99 % du code semble surconçu, et les développeurs ont de fortes incitations à maximiser leur propre caractère irremplaçable et leurs heures facturables
    Même des développeurs qui paraissent totalement mécaniques et dénués d’ego tombent souvent dans la surconception, et cela fonctionne inconsciemment
    Beaucoup de développeurs ne réfléchissent pas consciemment à chaque ligne de code qu’ils écrivent : ils se fixent un objectif, puis produisent le premier code qui les rapproche un peu de cet objectif, sans se rendre compte qu’à chaque étape il existait une meilleure alternative

    • D’après mon expérience, il est très rare que les incitations à accroître le caractère irremplaçable des développeurs et les heures facturables soient la cause de la surconception
    • Je me bats constamment avec ce problème
      D’abord, j’aime les puzzles intéressants. Or le code commercial, quand il est bien fait, est souvent assez ennuyeux ; inconsciemment, je finis donc par pousser des fonctionnalités amusantes à implémenter. Et par amusantes, j’entends des fonctionnalités qui rendent tout excessivement compliqué
      Ensuite, quand je suis en train de programmer quelque chose, tous les choix que je fais me paraissent évidents et nécessaires. Ce n’est que plus tard, après avoir pris de la distance avec le code et tenté de le comprendre avec un regard neuf, que je vois à quel point j’ai mis le bazar
      Pour la plupart des problèmes, la solution la plus visible est souvent assez complexe, et savoir où trouver une solution simple exige sagesse, savoir-faire et connaissance du domaine. Les solutions simples et propres sont rarement évidentes
      « Nous sommes en train d’implémenter petit à petit notre propre demi-file de messages. Utilisons simplement une file de messages standard », « Nous sommes en train de créer un protocole de framing binaire maison plein de bugs. Utilisons simplement protobuf/msgpack », « Ne créons pas un protocole RPC maison pour récupérer les données, utilisons REST sur HTTP. Comme ça, on pourra mettre nginx au milieu pour mettre en cache les réponses du backend et jeter aussi notre cache maison »
    • Cela me rappelle une phrase tirée d’une lettre d’un écrivain, du genre : « Je n’ai pas eu le temps de faire court, alors j’ai écrit une longue lettre »
      Au bout du compte, si l’on a le temps et que l’on est récompensé pour le faire, on peut écrire du code parfait, simple et sans répétition. Mais le plus souvent, ce qui est récompensé, c’est de sortir quelque chose, et de montrer sa compétence technique par la quantité de travail, d’intelligence et de capacité de conception investie dans cette sortie
      La conclusion naturelle, c’est que tout devient un amas gonflé et surconçu de solutions provisoires, réécrit tous les 3 à 7 ans
      Je n’ai pas consulté de données, mais j’imagine que la « demi-vie de réécriture » est corrélée au turnover ou à la durée moyenne de présence dans l’entreprise. Même si les gens faisaient davantage d’efforts pour ne pas surconcevoir, il est de toute façon très probable que le tout soit réécrit
      Pour un perfectionniste, c’est vraiment agaçant, mais il arrive que créer quelque chose de complexe et surconçu soit mieux récompensé que de réfléchir plus longtemps à la meilleure solution simple. Il existe peut-être de meilleures organisations, mais en 9 ans comme ingénieur logiciel, je n’en ai pas encore trouvé
      Les projets open source sont le meilleur contre-exemple qui me vienne à l’esprit, mais même de bonnes bibliothèques sont souvent réécrites ou sortent une nouvelle version quand le mainteneur change. Les incitations financières sont très différentes entre l’open source et le fatras d’entreprise que voient beaucoup d’ingénieurs logiciels à plein temps sur HN. C’est un peu comme comparer un article universitaire bien peaufiné à un e-mail professionnel écrit à la va-vite
    • Dans mon cas, la surconception vient généralement de l’inverse : du fait de trop réfléchir en écrivant du code, et d’avoir une idée préconçue de ce à quoi la codebase devrait ressembler
      Je me souviens que Casey, de Handmade Hero, appelait son style de programmation « basé sur la compression ». L’idée est d’écrire d’abord le code, puis de séparer progressivement ce qui va ensemble
      On abstrait quand il y a répétition, pas parce qu’on a consciemment conçu une abstraction. J’utilise de plus en plus cette approche
    • Si la conclusion « 99 % du code semble surconçu » produit des réponses du genre 99 %, ne pensez-vous pas que, même si ce que vous avez appris jusque-là est valable, il pourrait y avoir un problème avec le modèle mental que vous avez construit ?
      Cela ne veut pas nécessairement dire qu’il est faux en soi, mais s’il s’agit d’évaluer la qualité du travail des autres, il semble très probable qu’un fort biais soit en jeu
  • J’aime vraiment ce site, il me fait toujours rire. Ma partie préférée est surtout celle sur les microservices
    « grug se demande pourquoi gros cerveau prend le problème le plus difficile, découper correctement un système, et y ajoute en plus des appels réseau. pour grug, cela semble très déroutant »

    • J’aime ce site et je le relis souvent. Les gens que je connais doivent déjà en avoir assez du manifeste de développement logiciel qu’est grug brain
      « la complexité est très, très mauvaise »
      « si grug doit choisir entre complexité et combat en un contre un contre tyrannosaure, grug choisit tyrannosaure. au moins grug peut voir tyrannosaure »
  • J’ai quelques réserves sur la partie consacrée aux types
    grug dit que la valeur d’un système de types réside à plus de 90 % dans l’apparition magique de la liste de ce qu’on peut faire quand on appuie sur le point au clavier, mais dans mon entreprise, nos juniors déploient souvent en production du code qui casse à cause d’accès à null, et Sentry nous le signale
    Pendant les périodes de développement intensif, on voit environ un bug d’accès à null détecté par jour et par développeur junior
    Avec un vrai système de types doté d’une vérification statique, l’IDE dirait « ça peut être null, tu es sûr ? », ce qui serait extrêmement utile
    Et même sans typage statique, l’autocomplétion est possible
    Le passage « les chamans des systèmes de types à gros cerveau disent que la précision des types est au cœur du système de types, mais grug voit que ces chamans ne déploient pas souvent de code. Le code non déployé est peut-être correct dans un certain sens, mais ce n’est pas la correction dont parle grug » est impoli et inutile
    J’ai surtout déployé du code en C, PHP, Python, Haskell et Python typé, et dans les langages typés, le taux de bugs qui arrivent jusqu’en production est nettement plus bas. C’est l’une des raisons pour lesquelles j’aime les types
    De plus, le refactoring devient beaucoup plus simple. Quand on modifie quelque chose de largement utilisé, on peut repérer de manière fiable en quelques secondes, dans toute la base de code, les sites d’appel cassés, ce qui aide énormément à améliorer par itérations une base de code qui grossit

    • Est-ce que ce qu’il dit est faux ? Même d’après l’expérience que tu décris, tu ne sembles pas aller jusqu’à accepter un système de types qui impose des preuves formelles
      Tu acceptes plutôt un système de types de compromis, qui détecte certains problèmes et fournit surtout la magie de l’autocomplétion, sans t’enliser dans tous les détails nécessaires à une preuve complète de correction
    • C’est juste une blague. Je fais probablement partie de ceux dont on se moque, mais je ne pense pas qu’il faille le prendre trop à cœur
      Il semble considérer que le typage statique au niveau de C ou Java est acceptable, voire souhaitable, tandis que les choses plus sophistiquées qu’on voit dans Rust ou Scala sont une perte de temps. Je pense qu’il a complètement tort, mais c’est la vie
    • Le texte original n’est-il pas en faveur des langages typés ? J’ai l’impression qu’au final vous êtes sur la même position, donc je suis perplexe
    • Ici, je ne pense pas que le terme « chaman » désigne des gens comme toi
      J’ai compris « chaman des systèmes de types à gros cerveau » comme désignant non pas forcément quelqu’un qui écrit du code, mais par exemple quelqu’un qui vend des formations sur le sujet et excite les foules
      Plus haut dans l’article, il emploie aussi « chaman » à propos d’Agile, et il y a pas mal de gens dont l’activité ressemble davantage à de la vente de formations qu’à du vrai développement logiciel
    • J’ai déjà travaillé avec un « chaman des systèmes de types à gros cerveau ». À côté, ce texte relève plutôt d’une analyse très bienveillante et généreuse
      Travailler avec des gens obsédés par les hiérarchies de types est difficile à supporter, et leur justification reste généralement dans le monde des « et si » et des « mais ce n’est pas sound »
      Une grande partie de la dégradation de qualité provoquée par les systèmes de types vient de gens qui croient qu’en mettant suffisamment de types, on peut empêcher complètement les bugs, ce qui est faux
  • J’ai l’impression que dans les prochains mois tout le monde va monter dans le train HTMX, que ça va secouer la tête de beaucoup de jeunes développeurs, économiser énormément d’énergie dans le monde et rendre beaucoup de gens heureux
    Puis, quand ces jeunes curieux continueront à cliquer sur les liens de htmx.org et découvriront hyperscript, ce sera comme le moment où les vampires surgissent dans Une nuit en enfer

    • Que tout le monde monte dans le train HTMX, c’est une boucle infinie en JavaScript
      Quelqu’un se lasse de la complexité de JavaScript et crée une bibliothèque JavaScript simple, les gens affluent vers cette simplicité, la bibliothèque doit prendre en charge toutes les fonctionnalités du Web et devient complexe, puis quelqu’un d’autre, lassé de cette complexité, crée une bibliothèque JavaScript simple
      J’ai commencé en JavaScript pur, je me suis battu pendant des années avec IE5/6, jQuery nous a tous sauvés, j’ai sauté AngularJS parce que ce n’était pas terrible, et quand la bêta de React est sortie, je l’ai aimée pour ses idéaux de programmation fonctionnelle. Maintenant, je me fraie un chemin à travers la transpilation, le hot reload, Typescript et des piles de lourdes bibliothèques React
      J’ai aussi réalisé quelques projets avec Intercooler et HTMX. HTMX est globalement solide, mais ce n’est pas le premier train à passer par ce village
    • Ah, Carson Gross était donc l’auteur de grug brained developer et de htmx
      J’aimerais voir une vraie critique de htmx
      Personnellement, je pense que l’un des grands défis durables du Web a été de trouver comment bien mettre les pages à jour, et que nous avons continué à tout essayer. D’où une certaine fatigue, et certaines idées deviennent radicales ou se transforment avec le temps en bric-à-brac
      Htmx ressemble à une réaction façon grug : faire moins et s’en tenir à YAGNI
      L’avenir est incertain, mais des travaux comme les signals semblent toujours relever d’une quête sacrée. De nombreuses tentatives sont menées dans plusieurs directions, et nous sommes encore en train d’ouvrir ce front et d’autres
      MobX et Svelte ont déjà parcouru un long chemin eux aussi. Le voyage n’est pas encore terminé, et le fait de rester aux prises avec le monstre de la complexité n’est pas, selon moi, un signe de faiblesse — même si une pensée conservatrice ou grug pourrait le voir ainsi — mais l’effort nécessaire pour parvenir non pas à une approche seulement simple, mais à quelque chose de simple et bon
    • J’ai ri en lisant cette phrase, puis je suis allé vérifier
      _="on load wait 5s then transition opacity to 0 then remove me"
      Ah, non
      _="on htmx:error(errorInfo) fetch /errors {method:'POST', body:{errorInfo:errorInfo} as JSON} "
      Ah, non !
  • Je suis développeur depuis 30 ans, et je reconnais qu’à mes débuts j’étais arrogant et que je me croyais plus intelligent que les autres. À l’époque, j’étais du côté « gros cerveau » qui aime tous les démons de la complexité
    Dix ans plus tard, je m’étais rapproché du développeur « Grug brain », et aujourd’hui je me concentre sur la solution la plus simple qui fonctionne, tout en sachant qu’elle peut ne pas être parfaite. Et ce n’est pas grave, parce que cela permet de se rapprocher de ce qui est juste et de s’améliorer par itérations
    La meilleure chose qu’on puisse faire en tant que développeur, c’est supprimer du code. Là, une exigence que nous maintenions depuis deux ans vient soudain de ne plus en être une, et je suis vraiment enthousiaste à l’idée d’arracher beaucoup de code. Parce que tout va devenir plus simple

    • Quand on supprime du code, il y a une sensation agréable et difficile à décrire à l’arrière de la tête
      C’est comme si l’on sentait physiquement de l’espace se libérer
  • Grug est aussi apparu dans les commentaires de l’article Philosophy of Software Design il y a une semaine, et je trouve que la discussion y était plutôt bonne. https://news.ycombinator.com/item?id=38011938
    « J’ai exactement le même ressenti à propos de grug. Je ne pense pas que les gens soient réellement d’accord sur ce qui est simple, donc faire comme si sa propre “simplicité” était une évidence qu’un homme des cavernes approuverait aussi me semble relever de la pose »
    La simplicité est souvent l’une des choses les plus complexes à découvrir. J’ai vu beaucoup de gens convaincus que tout autour d’eux — sauf ce qu’ils font eux-mêmes — est complexe et doit être ramené de force à la simplicité. Ça ressemble à une posture dangereusement faible qui s’accroche à l’autorité

    • Bon point. Cela dit, je pense que le cœur du sujet est qu’une mauvaise philosophie encourage la complexité
      La philosophie du grug brain consiste à choisir la simplicité à tout prix, sauf quand elle est absolument impossible à éviter
      La philosophie du gros cerveau, vue par grug, consiste à choisir la réutilisabilité à tout prix, sauf quand elle est absolument impossible à éviter
      Le problème de cette philosophie est qu’elle fige les choix de conception de première génération et rend l’amélioration itérative plus difficile
      Il est vrai que la simplicité est difficile à trouver, mais la clé pour la trouver, c’est l’amélioration itérative
    • Ce qui est particulièrement réussi dans le texte de Grug, c’est qu’il est plein de nuance et d’humilité. Ce n’est pas de la pose
    • À mon avis, il suffit de mesurer le nombre de lignes de code
      Les minimums locaux se déplacent en fonction de la complexité de ce qu’on construit, donc plusieurs points de vue assez intelligents peuvent être vrais en même temps
      Ce n’est pas un indicateur parfait, mais il pointe dans la bonne direction, et il fonctionne très bien à l’échelle logarithmique
  • J’ai utilisé et expliqué d’innombrables fois le concept de clôture de Chesterton, et je suis content d’en connaître le nom
    C’est quelque chose qui arrive très souvent quand on travaille avec des développeurs débutants. Quand ils voient de la « vieille merde legacy », leur première réaction est de vouloir l’arracher ou tout jeter pour repartir de zéro
    Dans certains cas, les laisser essayer peut aussi être formateur, mais il est bon de se rappeler que ceux qui nous ont précédés n’étaient pas tous de parfaits idiots et qu’il y avait généralement une raison à ce choix
    Parfois, c’est vraiment du vieux code crade qu’il faut remplacer, mais même dans ce cas, il contient souvent une trace durement acquise de tous les recoins et cas limites qu’il faut comprendre et traiter pour construire quelque chose dans ce domaine

  • La partie sur les tests est vraiment bonne. Elle correspond exactement à ce que j’ai appris au fil des années
    Pour trouver des bugs, les tests d’intégration sont le bon niveau
    Les objets mock ont tendance à trop compliquer les choses, et même si j’en utilise encore parfois, j’évite de le faire de manière systématique
    Les tests unitaires sont trop fragiles face au refactoring, tandis que les tests d’intégration aident au refactoring

    • Mon astuce préférée consiste à écrire des tests d’intégration qui suivent un scénario de démo, puis à les lancer juste avant la démo. Deux fois si possible
    • Je suis fortement en désaccord. Les tests d’intégration fonctionnent très bien jusqu’à un certain niveau de taille ou de complexité, mais une fois ce seuil franchi, ils deviennent vraiment mauvais
      Les tests unitaires sont plus difficiles à écrire et à maintenir, mais ils sont beaucoup plus faciles à comprendre et à déboguer quand ils échouent, et tiennent donc bien mieux sur le long terme
      Le pire type de test, c’est le test d’intégration qui dépend en douce du fait qu’un autre test d’intégration ait été exécuté avant lui. Dans 99 % des cas ça passe, puis un changement modifie l’ordre et tout casse
    • Ma conclusion sur les tests est la suivante
      Si l’équipe a du code simple, les tests sont d’une grande aide. Mais si l’équipe n’a pas de code simple — et en général ce n’est pas le cas — il vaut mieux passer son temps à simplifier le code qu’à écrire des tests
    • Je pense que beaucoup dépend de ce qu’on considère comme une « unité »
      Prendre une seule fonction feuille comme unité est souvent un niveau trop bas, mais un module plus grand avec une interface relativement stable peut être une bonne unité productive à tester
  • « La complexité est très, très mauvaise »
    « La meilleure arme contre le démon spirituel de la complexité est le mot magique “non” »
    « Triste mais vrai : après avoir appris à dire “oui”, apprendre à rejeter la faute sur d’autres grug quand on échoue est le conseil de carrière idéal »
    Voilà la sagesse complexe de grug

  • Cela avait déjà été discuté à l’époque
    The Grug Brained Developer - https://news.ycombinator.com/item?id=31840331 - juin 2022, 374 commentaires

    • La complexité reste très mauvaise