1 points par GN⁺ 2025-08-30 | 1 commentaires | Partager sur WhatsApp
  • En conception logicielle, choisir en permanence « la chose la plus simple possible » est un conseil efficace
  • Une excellente conception de système n’a rien de spectaculaire et résout en pratique les problèmes avec le minimum de composants
  • Lorsqu’on recherche une solution simple, on peut faire du principe YAGNI (You Aren't Gonna Need It) une philosophie de conception centrale, en n’étendant progressivement le système que lorsque de nouvelles exigences apparaissent
  • Même si la définition de la « simplicité » fait débat, un système avec peu de composants, des couplages faibles et une bonne stabilité est ce qui s’en rapproche le plus
  • L’obsession pour une scalabilité excessive rend le codebase moins flexible ; à long terme, une conception simple et fidèle aux besoins réels est plus avantageuse

À la recherche de la chose la plus simple possible

Lorsqu’on conçoit un système logiciel, il est important de faire « la chose la plus simple possible ». Cette approche s’applique à presque toutes les situations : correction de bugs, maintenance d’un système existant ou conception d’une nouvelle architecture. Beaucoup d’ingénieurs rêvent d’un système « idéal » — bien organisé, presque infiniment extensible et proprement distribué — mais, en pratique, il est plus efficace de bien comprendre le système actuel puis de choisir la solution la plus facile.

La simplicité sous-estimée

  • La conception de systèmes exige de savoir utiliser divers outils : serveurs d’applications, proxies, bases de données, caches, files d’attente, etc.
  • Les ingénieurs juniors ont davantage tendance à vouloir bâtir des structures complexes à l’aide de nombreuses technologies, alors que la véritable maîtrise consiste au contraire à éliminer l’inutile
  • Une excellente conception logicielle paraît terne ; elle donne même l’impression que le problème a été résolu plus facilement qu’on ne l’imaginait
  • Par exemple, Unicorn et l’API REST Rails exploitent les fonctionnalités de base d’Unix pour offrir des garanties essentielles avec une structure minimale (isolation, montée en charge, reprise, etc.), ce qui en fait une conception remarquable

Une manière de penser pour implémenter simplement

  • Par exemple, pour ajouter du rate limiting à une application Golang, on peut utiliser un stockage externe comme Redis, mais sauf nécessité absolue, on peut d’abord essayer une méthode plus simple, comme un compteur en mémoire
  • Si cette approche suffit, on peut repousser l’ajout d’une infrastructure plus lourde
  • Cela permet une évolution progressive du développement, en n’étendant le système que lorsque de nouveaux besoins apparaissent réellement
  • C’est une approche qui place le principe YAGNI au premier rang de la conception

Les pièges de la simplicité et ses limites réalistes

1. Le phénomène du Big Ball of Mud

  • Si l’on répond immédiatement à chaque demande, on risque de finir avec un codebase de type « big ball of mud », complexe et difficile à maintenir
  • Mais les modifications improvisées (hack) ne relèvent pas de la simplicité ; elles ajoutent au contraire davantage de complexité à la compréhension et à la maintenance
  • Pour trouver une solution réellement simple, il faut comparer de nombreuses approches et mener un travail d’ingénierie rigoureux

2. Définir la simplicité

  • Il est difficile d’obtenir un consensus sur ce qu’est la « simplicité »
  • En général, un système simple comporte peu de pièces mobiles (éléments actifs), des couplages faibles entre composants et des interfaces bien définies
  • Exemple concret : les processus Unix et Unicorn ne partagent pas la mémoire, ce qui renforce leur simplicité ; comparés à Puma ou Redis, leur connectivité interne est plus faible
  • Quand le choix n’est pas clair, on peut considérer que la solution la plus simple est celle qui demande le moins de maintenance

3. Critique de l’obsession de la scalabilité

  • La « méthode simple » n’est pas toujours adaptée à un trafic de grande ampleur
  • Mais concevoir d’emblée un système complexe pour anticiper une future montée en charge brutale est le plus souvent un effort inutile
  • Dans la majorité des cas, il suffit que le code absorbe un trafic multiplié par 2 à 5 ; au-delà, il est plus rationnel de réagir lorsque le problème se présente réellement
  • Une conception trop centrée sur la scalabilité nuit à la flexibilité du code ; découper la structure plus que nécessaire peut au contraire compliquer l’implémentation de certaines fonctionnalités et exiger une gestion transactionnelle complexe

Conclusion

  • Avec le temps, on devient plus pessimiste quant à notre capacité à prévoir les besoins futurs d’un système
  • En pratique, comprendre avec précision l’état actuel d’un système est déjà suffisamment difficile, et c’est là l’un des principaux obstacles à une bonne conception
  • Il existe globalement deux manières de développer un logiciel
    • Concevoir en anticipant les besoins futurs
    • Répéter la chose la plus simple possible, en restant fidèle aux besoins présents
  • La seconde approche est en pratique plus efficace, et une pensée centrée sur YAGNI et la simplicité produit de meilleures conceptions sur le long terme

Annexe : discussion Hacker News et origine de l’expression

  • À l’idée selon laquelle la simplicité architecturale perd de son sens à grande échelle, l’auteur répond au contraire que plus l’échelle augmente, plus une structure simple devient importante (face à la complexité des interactions entre fonctionnalités)
  • L’expression « Do the simplest thing that could possibly work » a été créée par Ward Cunningham et Kent Beck

1 commentaires

 
GN⁺ 2025-08-30
Avis Hacker News
  • Je pense que cette approche peut bien fonctionner dans des domaines simples. Mais même après avoir longtemps travaillé dans de grandes entreprises tech, je suis toujours surpris par la complexité requise. Même les problèmes métier les plus simples peuvent prendre plus d’un an à être résolus, ou se cassent souvent à cause d’innombrables cas limites et problèmes d’échelle. Les personnes qui prônent la simplicité n’ont tout simplement pas d’expérience à grande échelle. Même en regardant un codebase vieux de 10 ans, il y a tellement de choses à prendre en compte que les réécritures échouent souvent elles aussi. Comme dans la métaphore de la barrière de Chesterton, il faut la sagesse de ne pas supprimer quelque chose à la légère quand on ne connaît pas la raison de son existence

    • Je pense que c’est un malentendu classique causé par le fait que les ingénieurs logiciel communiquent mal entre eux. Comme le dit le titre de l’article, il s’agit de faire « la chose la plus simple possible ». La complexité est inévitable dans les problèmes complexes, mais l’idée est de se méfier de l’erreur qui consiste à rendre les choses inutilement plus complexes. Il ne s’agit pas d’éviter totalement la complexité, mais de rester vigilant face à l’habitude de surcomplexifier

    • Comme cela a été souligné, la complexité ne vient pas forcément du domaine lui-même. Elle peut venir d’une mauvaise conception logicielle. Si le système est rempli de dépendances et d’effets de bord, c’est que la séparation des responsabilités et la gestion du couplage ont échoué. Le refactoring devient presque impossible et, si la culture d’organisation ne s’améliore pas, on ne fait qu’ajouter de nouveaux problèmes pendant le refactoring. Malgré cela, on peut résoudre des problèmes complexes avec une simple séparation des responsabilités et une composition simple. C’est difficile, mais les développeurs seniors ont tout intérêt à adopter fermement cette vision pour maximiser les chances de réussite

    • En mentionnant que l’auteur est Staff Engineer chez GitHub, je pense qu’il a lui aussi une expérience suffisante des systèmes à grande échelle

    • Les systèmes legacy vivent aux frontières. Même dans les systèmes réels, comme dans un espace multidimensionnel où les points se concentrent sur les surfaces de bord à mesure que les dimensions augmentent, les vrais utilisateurs travaillent surtout près des limites du système. Le vieux système existant finit donc par être celui qui absorbe au mieux tous ces bords

    • Dans mon précédent poste, une grande partie de la complexité venait de tentatives de refactoring ou d’amélioration qui avaient échoué, été abandonnées en cours de route, ou étaient restées inachevées. Je me suis souvent demandé si nous aurions hérité d’un système plus simple si cela avait été empêché plus tôt. Cela ne veut pas dire qu’il ne faut jamais faire de refactoring ni d’amélioration, mais je pense qu’il faut planifier pour couvrir clairement 100 % des cas d’usage, sécuriser le budget et les jalons, puis garantir une amélioration progressive

  • J’aurais aimé que l’origine de l’expression « la chose la plus simple possible » soit explicitée. C’est un principe que l’inventeur du wiki, Ward Cunningham, et Kent Beck utilisaient souvent à la fin des années 1980 en travaillant ensemble. Pendant qu’ils programmaient, ils se rappelaient sans cesse ce principe, et c’est ensuite devenu un thème important dans leurs présentations et leurs écrits. Comme avec l’exemple de la porte fermée, l’article mentionne aussi que ce qui semble « simple » peut varier selon la situation. Trouver la solution simple n’est pas toujours simple. Ils avaient aussi conscience que cette approche pouvait laisser de la dette technique, mais la priorité était d’abord de faire fonctionner le code. Personnellement, j’aurais aimé que cet article parle davantage de l’aspect dette technique

    • Kent Beck a ensuite formalisé l’Extreme Programming. Cette méthodologie est un ensemble de pratiques destinées à permettre à un système simple d’évoluer naturellement au gré des changements de besoins

    • J’avais déjà entendu cette expression de la part d’un collègue qui l’utilisait comme une devise de vie, mais je ne savais pas que Ward Cunningham en était à l’origine. L’expression est devenue si répandue que le plus grand honneur semble être que plus personne ne connaisse l’auteur original

    • J’ai trouvé intéressant qu’on parle du wiki. Dans un ancien poste, nous gérions les projets avec Lotus Notes, qui mettait en évidence les documents modifiés, ce qui était utile. Dans le projet suivant, on n’utilisait qu’un wiki, mais il était impossible de voir d’un coup d’œil quels documents avaient changé, si bien qu’il était devenu en pratique inutilisable. C’était simple, mais trop simple, au point d’en perdre en utilité

  • La définition de « ça marche » a été l’un des sujets les plus débattus tout au long de ma carrière. La phrase « ce n’est pas parce que ça marche que ce n’est pas cassé » parle intuitivement à tous ceux qui ont déjà réparé quelque chose de leurs mains. Les réparateurs bricolent parfois avec un outil cassé avant de décider de le remplacer, tandis que les développeurs semblent moins ressentir ce besoin de dire « il faut le réparer »

    • La période la plus difficile de ma carrière a été dans une entreprise où une équipe adorait les prototypes. Cette équipe fabriquait très vite une preuve de concept, faisait une démo aux dirigeants, puis la déployait immédiatement. Les dirigeants s’imaginaient alors que, si cela avait été terminé si vite, cela pouvait être mis en production tout de suite. Ensuite, l’équipe responsable ouvrait le code et découvrait que tout ce qui est indispensable — sécurité de bout en bout, validation, gestion des erreurs, etc. — manquait. Il fallait finalement tout reconstruire depuis le début, et les dirigeants croyaient à tort que l’équipe de déploiement compliquait les choses inutilement

    • J’ai vu quelque part une citation marquante : « Il ne suffit pas qu’un programme fonctionne. Il doit fonctionner pour les bonnes raisons. » C’est essentiellement le même message

    • Ce genre de conversation est une partie importante du métier. On peut dire qu’un système « marche » au sens où il produit la sortie souhaitée, tout en considérant qu’il échoue encore en matière de fiabilité ou de coût

    • Dans mon travail, la définition de « ça marche » dépend de l’endroit où mon employeur veut investir les ressources, c’est-à-dire mon temps. Si j’ai le droit de consacrer du temps à l’amélioration de la qualité, je fais de mon mieux. Si, au contraire, on veut simplement atteindre un objectif ou cocher une checklist, je travaille dans ce sens. J’estime qu’on obtient les résultats qu’on mesure, donc je peux conseiller, mais la décision ne m’appartient pas

  • L’ironie de ce type de conseil, c’est que ceux qui savent vraiment bien l’appliquer sont déjà des experts très expérimentés. Par exemple, comment savoir ce qu’est « la chose la plus simple », ou comment juger qu’elle marchera vraiment ? Récemment, j’ai moi-même commis une erreur de gestion des espaces de noms XML dans un importeur XLSX que j’avais développé, en supposant qu’Excel utiliserait toujours uniquement l’espace de noms par défaut. Puis un jour, je suis tombé sur un fichier utilisant d’autres espaces de noms, et tout a cassé. Le plus simple aurait été de supprimer les préfixes et de traiter ça ainsi, mais pour mon futur moi, j’ai passé quatre heures à réécrire tout le parseur pour qu’il gère correctement les espaces de noms. Faire « la chose la plus simple » n’est en réalité pas si simple, et l’expérience aide à mieux juger. Mais arrivé à ce niveau d’expérience, on peut aussi se dire qu’on n’a plus vraiment besoin de ce conseil

    • Je pense que le corps de l’article expliquait aussi pourquoi ce conseil est difficile à appliquer. Le point essentiel, c’est que « pour trouver la solution la plus simple, il faut envisager plusieurs approches, ce qui demande au final une vraie réflexion d’ingénierie »

    • Dans notre entreprise, nous avons un principe : « n’ajoutons pas de code dans la mauvaise direction ». Même pour une implémentation partielle, nous codons uniquement dans une direction qui facilitera l’évolution future. C’est du KISS, mais on n’autorise jamais les rustines

    • Pour moi, la simplicité se juge à « ce qui est le plus facile à faire évoluer ». Un service unique qui ne dépend pas d’abstractions complexes ni d’une infrastructure lourde est finalement plus simple à faire évoluer. La personne qui lit le code peut le comprendre immédiatement, et la transmission comme le débogage sont plus faciles. Cela dit, j’ajoute une abstraction quand elle est vraiment nécessaire, et j’ajoute de l’infrastructure quand elle est indispensable. L’important, c’est de toujours se demander si c’est la structure la plus facile à expliquer au moment de passer le relais. Avant, je cherchais à tout abstraire au maximum, à tout découper par services, à tout rendre piloté par la configuration, avec presque plus de code, mais en pratique les transitions et les passations ont complètement échoué. Désormais, je ne complexifie la structure qu’en cas de nécessité absolue, et je garde par défaut une simplicité intuitive. Au final, cela aide autant pour l’onboarding des nouveaux arrivants que pour la correction des bugs et les vraies transitions

    • L’IA vibecoding, c’est un peu pareil. Plus on accumule de l’expérience et du savoir-faire, plus il devient facile de choisir les bonnes tâches et de piloter les agents

    • Beaucoup de gens semblent manquer le fait que « la chose la plus simple » ne veut pas dire une rustine ou un colmatage en urgence. Plus une approche est simple, plus elle exige en réalité de réflexion et de compréhension du système, et c’est justement ce que disait le début de l’article. Beaucoup semblent avoir lu seulement le titre avant d’y projeter leurs frustrations

  • En général, dès que j’entends ce genre de principe ou d’affirmation forte, je deviens méfiant. Quand quelqu’un parle du développement logiciel comme s’il existait une réponse universelle, c’est souvent qu’il ne comprend pas vraiment le sujet. La conclusion des développeurs réellement expérimentés, c’est que le logiciel est difficile et demande de la prudence. Il n’existe aucune réponse miracle. Il faut garder l’esprit ouvert et faire preuve de considération

    • La simplicité — autrement dit l’inverse de la complexité — est presque toujours le critère numéro un quand on compare des alternatives de conception logicielle. La raison est simple : au bout du compte, ce sont des humains qui doivent concevoir, approuver, implémenter et maintenir le système. Mais juger de la simplicité est extrêmement difficile, et l’ingénieur moyen du secteur n’inspire pas assez confiance pour qu’on s’en remette à son jugement. De plus, le mot même de « simplicité » s’est diffusé comme un buzzword vide de sens, au point qu’on l’utilise souvent seulement pour contester un argument sérieux par un « ça, c’est plus simple ». Le responsable d’équipe devrait savoir repérer ce genre de problème, mais le niveau des managers devient de moins en moins fiable, ce qui rend les choses encore plus difficiles

    • Il y avait aussi une phrase marquante dans l’article. Un véritable maître sait non pas « en faire plus », mais « en faire moins » : comme dans une scène où le novice multiplie les gestes spectaculaires, tandis que le maître bouge peu et ne porte qu’un coup décisif

    • En lisant l’article, j’ai d’abord été un peu agacé, mais je pense qu’il vise juste sur la nature des tâtonnements : les rustines n’ajoutent qu’une complexité supplémentaire. Le problème, c’est quand ce genre de principe est surappliqué comme un ordre venu du management : on répond alors trop simplement à des problèmes complexes, ce qui rend la transmission des connaissances difficile et laisse ensuite un rattrapage encore plus complexe. À l’inverse, si les choses deviennent plus compliquées que nécessaire, c’est souvent parce qu’on a accumulé trop d’expédients et de rustines, puis qu’on essaie de tout corriger d’un coup en allant cette fois trop loin. Au final, les développeurs doivent intervenir activement dans les discussions afin d’orienter les décisions dès le départ vers plus de sagesse

    • Je ne pense pas que ce soit au point d’être un signal d’alarme. La complexité inutile s’accumule tous les jours, donc il faut absolument des gens pour défendre la simplicité. Les designers, les product managers, et même les clients ou les architectes ont tous tendance, par instinct, à ajouter de la complexité

    • Je comprends ton point de vue, mais je note aussi que cela finit toujours par revenir à « tout est affaire de compromis » ou « il n’y a pas de repas gratuit ». Toute généralité est un condensé d’expérience de terrain, donc on ne peut pas entièrement s’en débarrasser. Le vrai problème, c’est quand un concept pratique finit par se transformer en rumeur excessive ou en quasi-religion, au point qu’il ne reste plus que des débats absurdes sur des noms de dossiers

  • À force de construire plusieurs systèmes de 0 à 1 dans des startups (de la Seed à la Series C), j’ai intégré un principe : « la simplicité, c’est la robustesse ». Que ce soit dans une conception initiale ou dans l’amélioration d’un système existant, il est très facile de trop concevoir. Les besoins des clients évoluent sans cesse, et même si l’on essaie d’anticiper les besoins futurs, on se trompera forcément. La simplicité ne réduit pas seulement les erreurs, elle fournit aussi une base qui permet de faire évoluer facilement la structure. Il faut préparer autant que possible X, Y et Z, mais en visant malgré tout « la chose la plus simple » afin de préserver la marge de manœuvre et l’extensibilité future. La complexité augmente inévitablement les contraintes, et plus elle s’accumule avec le temps, plus la stack devient fragile

  • Je pense qu’il faut avoir essayé jusqu’à un certain point de concevoir un « système idéal » pour finalement arriver à « la chose la plus simple ». Il faut beaucoup de savoir-faire pour créer un système facile à lire et facile à faire évoluer. Une amélioration véritablement « simple » naît elle aussi de l’expérience et d’une compréhension profonde

  • C’est dans la même veine que la loi de Gall. Selon cette théorie, un système complexe qui fonctionne est toujours parti d’un système simple auquel on a progressivement ajouté de la complexité. Un système conçu complexe dès le départ fonctionne rarement bien. Il faut donc commencer par construire le système le plus simple possible, puis lui ajouter progressivement de la complexité selon les exigences

    • Alors quand faut-il s’arrêter ? Existe-t-il un « boss final » de la complexité, ou un seuil critique ?
  • Je suis d’accord avec l’esprit de l’article, mais je pense que l’arrivée de l’infrastructure cloud a changé la définition de la « simplicité ». Autrefois, l’opposition était « quelque chose de simple mais non scalable » contre « quelque chose de complexe mais scalable », mais ce n’est plus vraiment le cas. Une solution de rate-limiting en mémoire est simple sur un seul serveur, mais dès qu’il y a deux serveurs, cela devient immédiatement un problème d’état distribué. À l’inverse, des managed services comme DynamoDB ou ElastiCache fournissent une source de vérité unique aussi bien pour un seul nœud que pour 1000 serveurs, ce qui réduit fortement la complexité. Si l’on considère qu’un système simple est un système robuste, alors utiliser un managed service peut être plus fondamentalement simple. Cela élimine des problèmes récurrents comme la perte de données ou la gestion de l’état distribué. Aujourd’hui, la définition de « la chose la plus simple » semble avoir évolué vers une bonne utilisation des managed services sans gestion directe. Désormais, éviter les dépendances externes n’est plus forcément l’option la plus simple ; il est souvent plus efficace, en temps comme en coût, de tirer parti de systèmes validés et isolés pour minimiser la complexité

    • Je ne pense pas que ce soit un phénomène propre au cloud. Même sur un seul serveur, on peut avoir exactement la même discussion entre flat file, sqlite, postgres et d’autres choix de stockage. La réalité d’aujourd’hui, c’est qu’il existe énormément de logiciels qui, pour un surcroît de complexité relativement faible, apportent des capacités immenses. Bien sûr, chaque choix implique des compromis, donc le discernement reste indispensable. Choisir d’emblée un managed service (Amazon, par exemple) n’est pas forcément la bonne réponse. J’ai d’ailleurs entendu plusieurs retours de regrets après avoir adopté DynamoDB pour une échelle qui ne le justifiait pas
  • J’adhère à la maxime : « aussi simple que possible, mais pas plus simple que cela ». J’essaie toujours de suivre ce principe, mais je me demande constamment si je passe à côté de complexités inutiles parce que je connais mal les technologies récentes, ou si au contraire tout le monde est en train de se laisser happer par de la complexité superflue. Sans les utiliser sur de vrais projets, il est difficile de savoir si ces outils valent vraiment le coup ; à l’inverse, j’ai aussi vu qu’imposer les derniers outils à un projet réel juste pour son propre apprentissage nuisait à l’équipe

    • Je vis un cauchemar similaire. J’ai un supérieur toujours passionné par les tout derniers logiciels, et je dois donc évaluer en conditions réelles des outils dont l’intérêt est parfois douteux. C’est pesant qu’on me demande de poursuivre ce type d’exploration semaine après semaine, indépendamment de tout impact concret

    • En pratique, je pense qu’il faut d’abord faire marcher les choses de la manière la plus simple possible — même manuellement si nécessaire — puis n’ajouter la fonctionnalité complète qu’au moment où le besoin devient réel. Même si on a perdu du temps au départ à tout automatiser ou outiller trop tôt, l’expérience la plus importante reste d’avoir compris plus tard pourquoi c’était réellement nécessaire

    • Ce sentiment m’est très familier. Moi aussi, je me retrouve toujours dans ce genre de texte et j’essaie de mettre la simplicité en pratique, mais je doute sans cesse : est-ce vraiment de la sagesse et du pragmatisme, ou simplement un manque d’expérience et de compétence ?

    • C’est justement pour cela que j’essaie de faire très attention à ne pas tomber dans le « développement orienté CV »