Ask HN : quelle est la meilleure base de code pour apprendre la conception logicielle ?
(news.ycombinator.com)- J’essaie d’améliorer mes compétences en conception logicielle, et on m’a conseillé d’étudier des bases de code existantes bien conçues
- Je me demande quelles bases de code accessibles publiquement sont considérées comme l’étalon-or en matière de conception logicielle
1. Bases de code recommandées
- Grands projets / projets de référence
- Git, Postgres, CPython
- le « lieutenants model » du noyau Linux
- UNIX v6, les BSD
- Frameworks / bibliothèques
- Spring Framework
- Laravel
- la bibliothèque standard de Rust
- Codemirror 6
- Systèmes / serveurs
- Jeux / cas particuliers
- Ressources pédagogiques / d’apprentissage
- xv6 (cours OS du MIT)
- pytudes (Peter Norvig)
- Autres
- Monocypher (bibliothèque de chiffrement)
- l’implémentation du langage Tcl
2. Lecture de code vs apprentissage par la documentation / la conception
- Les limites du code seul
- une base de code montre l’implémentation, mais masque souvent l’intention de conception et les compromis
- L’importance des documents de conception
- les traces de décision comme les ADR (Architectural Decision Records), les RFC de Rust ou les PEP de Python sont bien plus utiles pour apprendre la conception
- rédiger soi-même des documents de conception peut aussi constituer un excellent entraînement
- Livres et références recommandés
- The Architecture of Open Source Applications
- Code Reading (Spinellis)
- Beautiful Code (O’Reilly, ISBN-10: 0596510047)
- des ouvrages sur le refactoring / le legacy code
3. Une approche d’apprentissage centrée sur la pratique
- Expérience et essais-erreurs
- on apprend la conception en rencontrant les problèmes de manière répétée, puis en apprenant à les éviter
- lire du code ne suffit pas ; on progresse surtout en écrivant soi-même du code et en résolvant ses échecs
- Apprentissage guidé par l’intérêt
- on apprend plus en profondeur quand on construit un projet qui nous intéresse réellement
- Un coût de l’échec relativement faible
- contrairement à l’ingénierie physique, le coût de l’échec en logiciel est plus faible, ce qui rend l’apprentissage par tentative et erreur particulièrement efficace
4. Débat sur la nature de l’ingénierie logicielle
- La thèse d’une ingénierie encore immature
- si cinq ingénieurs proposent cinq solutions différentes, cela peut être vu comme le signe d’une discipline encore immature en tant qu’ingénierie
- La thèse d’un domaine propice à l’expérimentation
- le logiciel est moins contraint, ce qui autorise de nombreuses solutions ; contrairement à l’ingénierie physique, il n’existe pas toujours une réponse unique
- À la frontière entre art et ingénierie
- la conception peut aussi relever d’une pratique artistique, avec une dimension esthétique, tout en restant de l’ingénierie lorsqu’elle répond à des exigences fonctionnelles
- le logiciel se situe entre flexibilité artistique et rigueur d’ingénierie
5. Méthodes d’apprentissage alternatives
- Analyser du mauvais code
- corriger une base de code mal conçue peut être tout aussi formateur qu’étudier du bon code
- Apprendre à partir de sa propre base de code
- beaucoup considèrent la base de code de leur propre équipe comme la meilleure source d’apprentissage
- mais si le code de l’équipe est mauvais, il est utile de le compléter par des exemples externes
- Apprentissage adapté au domaine
- le plus efficace est de lire des bases de code proches du type de problème que l’on veut résoudre
Principaux enseignements
- les bases de code bien conçues sont utiles, mais l’apprentissage doit aller de pair avec la compréhension des intentions de conception et l’expérience des essais-erreurs
- plus que la simple lecture de code, ce sont surtout les documents de conception et les traces de décision qui servent de ressources d’apprentissage clés
- des projets de très haute qualité comme Git, Postgres, CPython ou la bibliothèque standard de Rust ont une forte valeur pédagogique
- sur le long terme, apprendre à partir de mauvais code et de son propre code est souvent plus concret que de ne regarder que du bon code
Résumé des principaux commentaires
Recommandations de bases de code représentatives (CraigJPerry)
- Serveur mail Postfix
- son architecture centrée sur la sécurité montre une structure proche des microservices avant même que le terme existe
- là où les microservices modernes mettent l’accent sur la distribution à grande échelle dans de grandes organisations, Postfix a été conçu pour la sécurité et la simplicité
- Spring Framework
- on y retrouve une culture qui prend profondément en compte les besoins des développeurs Java en environnement d’entreprise
- c’est un bon exemple d’approche de conception orientée utilisateur
- Git
- une fois compris le concept de base de données objet (blob, tree, commit) et celui de référence, le reste n’est qu’une extension progressive
- l’extension cohérente d’un noyau de concepts est présentée comme un bon exemple de conception
- Varnish
- un reverse proxy haute performance, avec une base de code suffisamment bien structurée pour servir aussi d’outil d’apprentissage
- Lieutenants Model du noyau Linux
- ce n’est pas une base de code à proprement parler, mais c’est une référence utile pour la gestion de logiciels à grande échelle
- il ne s’agit pas seulement de « code bien conçu », mais de cas où les décisions de conception laissent une forte impression
L’importance d’apprendre à partir de bases de code réelles en entreprise (crystal_revenge)
- la plus grande valeur pédagogique se trouve souvent dans la base de code de sa propre équipe
- c’est dans le lien souvent chaotique entre exigences réelles et implémentation qu’on fait l’expérience simultanée des bons et des mauvais choix
- parmi les contraintes du réel, la plus importante est souvent la pression du temps ; l’essentiel est donc d’apprendre à équilibrer conception idéale et réalité
- un bon logiciel est avant tout un logiciel qui répond aux besoins des utilisateurs, et l’expérience répétée aide à concevoir avec plus de chances de succès
Discussions passées et liens utiles (sprobertson)
- le même sujet a été abordé plusieurs fois sur HN
Code vs documents de conception (alphazard)
- une base de code n’est que le résultat d’une implémentation, pas la conception elle-même
- pour apprendre la conception, rédiger des documents de design est plus efficace
- un document doit être suffisamment clair pour qu’une autre personne puisse l’implémenter tel quel
- lister les alternatives et expliquer pourquoi elles ont été écartées constitue une preuve du travail de conception
- un bon concepteur est quelqu’un qui explore un espace de conception plus large puis choisit le bon point d’équilibre
L’importance de comprendre l’ensemble du système (RossBencina)
- le processus consistant à comprendre une base de code dans son ensemble a énormément de valeur
- cela ne sert pas seulement à lire du code bien conçu, mais aussi à apprendre à voir la vue d’ensemble d’un système
- visualiser les relations via des diagrammes, par exemple en UML, peut aider
- approche recommandée pour apprendre :
- lire le code de logiciels similaires à ce que l’on développe soi-même est particulièrement efficace
- comme point de départ, il recommande du code dans un domaine déjà familier (framework web, serveur web, bibliothèque standard Python, VSCode, etc.)
- il vaut mieux commencer par de petits programmes ou des domaines connus
Les critères d’une bonne conception (mamcx)
- une bonne conception correspond à des objectifs et des idées ; la base de code ne montre que le degré de leur implémentation
- une bonne conception ne se résume pas à des adjectifs comme « rapide » ou « sûr » ; elle doit inclure des considérations concrètes et la trace des compromis
- on peut observer ces caractéristiques dans des cas comme Erlang, les premières versions de Pascal ou la conception de nombreux SGBDR
- la bibliothèque standard de Rust, qui met l’accent sur la sécurité et la cohérence, est une bonne ressource d’apprentissage car le code et la documentation reflètent fidèlement ces priorités
Les décisions de conception invisibles (ben30)
- dans une base de code bien conçue, le plus important est souvent ce qui ne se voit pas
- exclure la complexité, éviter les abstractions inutiles ou refuser certains patterns sont des décisions d’absence essentielles
- pour conserver ce contexte, il recommande d’utiliser des ADR (Architectural Decision Records)
- ils permettent d’enregistrer les alternatives, les raisons de leur rejet et les fondements du choix retenu
- cela aide énormément les futurs mainteneurs, mais aussi les outils d’IA
- pour apprendre, il est donc efficace d’examiner non seulement le code, mais aussi les documents de décision de conception comme les ADR, RFC ou PEP
5 commentaires
J’ai lu plusieurs fois le code d’
express.jsaprès être tombé sur une interview où Evan You (créateur de Vue.js et Vite) disait que TJ Holowaychuk l’avait conçu de façon propre et élégante. Je n’ai pas réussi à en saisir toute l’architecture d’ensemble, mais j’ai eu l’impression générale que le code n’était pas complexe et qu’il ne contenait que la logique strictement nécessaire, de manière très nette.Les commentaires sont aussi bien rédigés, donc même si le code a 10 ans, c’était pratique pour comprendre l’inférence de types ou le format des DTO.
Prendre comme référence un article de blog de 2009 recouvert de commentaires spamés...
Commentaire Hacker News
Je ne sais pas si je suis le seul dans ce cas, mais j’ai l’impression que la méthode la plus efficace consiste à se heurter plusieurs fois à de vrais problèmes et à apprendre soi-même comment les éviter. Avec le temps, on finit naturellement par simuler mentalement les problèmes qui pourraient survenir, et au bout du compte, le design consiste justement à anticiper et éviter divers problèmes futurs, à évaluer soigneusement les compromis entre les problèmes qu’on veut éviter, l’effort nécessaire pour les éviter, et la possibilité de résoudre plusieurs problèmes avec un seul design.
Moi aussi. Les approches du type « résoudre des exercices » ou « étudier un codebase » ne me convenaient pas. J’apprends naturellement en construisant quelque chose qui m’intéresse vraiment, en cherchant la précision et la rigueur dans les exemples. Mais parfois, j’ai encore l’impression que mon niveau est insuffisant. Je pense que si je pouvais lire du code aussi facilement qu’un livre et en visualiser le fonctionnement dans ma tête, l’apprentissage lui-même serait plus amusant.
Ce que je retiens de l’idée d’apprendre en se cognant plusieurs fois aux problèmes, c’est que le domaine du software engineering n’est pas encore mûr. Si on construisait des ponts ou des maisons de cette façon, ou si les chirurgiens se formaient ainsi, ce serait inquiétant rien que d’y penser. Avec le temps, des standards et des normes finiront par s’imposer, mais pour l’instant la situation est encore très fluide. Si l’on réunit cinq ingénieurs logiciel et qu’on leur donne un problème, on obtiendra non seulement cinq solutions totalement différentes, mais aussi de forts désaccords sur laquelle est la bonne. Je ne pense pas qu’on puisse parler d’ingénierie sérieuse avec une attitude du type « on reconnaît une bonne solution quand on la voit ».
Moi aussi, c’est de cette façon que j’ai appris régulièrement jusqu’ici, et je continuerai sans doute ainsi. Apprendre à partir de vrai code de production serait un nouveau défi pour moi. Je ne sais pas à quel point ce sera utile, mais ça a l’air amusant en tout cas.
Je trouve que c’est un peu comme apprendre à conduire en montant directement dans une voiture, en provoquant un accident, puis en se promettant de ne pas recommencer la fois suivante. En réalité, il faut les deux approches. Sur route normale, on dépasse rarement les limites, donc c’est difficile à appliquer directement, mais en course automobile, il est indispensable de savoir exactement jusqu’où on peut pousser la machine. Bien sûr, je ne pense pas qu’il faille traiter notre métier comme une compétition. Mais si on ne lit pas et qu’on n’étudie pas, cela prendra littéralement énormément de temps, et les accidents comme les pannes n’en finiront pas. Donc moi, je dirais qu’il faut lire, encore et encore. On ne ressent peut-être pas le besoin immédiatement, mais un jour, avec l’expérience, ces connaissances serviront forcément quelque part, et on évitera de se retrouver démuni, comme lorsqu’on apprend pour la première fois à rétrograder en frein moteur dans une descente.
C’est exactement ça.
La première chose qui me vient à l’esprit en entendant cette question, c’est « le codebase de votre équipe ». Il n’existe pas de moyen plus efficace d’apprendre le software design que de comprendre en profondeur pourquoi, face à de vrais problèmes, de bonnes solutions comme de mauvaises ont été adoptées. Le logiciel est par essence cette couche intermédiaire complexe entre les besoins des utilisateurs et le comportement des machines. Sans ce chaos, tout aurait déjà été automatisé et le logiciel lui-même ne serait plus nécessaire. En logiciel, poursuivre uniquement un idéal abstrait conduit souvent à de mauvaises décisions. En pratique, on réduit les tâtonnements en comprenant « pourquoi tel choix a été fait sous telle contrainte ». En même temps, il faut apprendre des méthodes de travail concrètes pour avancer vite et efficacement. Dans la réalité, la plus grande difficulté, c’est la contrainte de temps. Elle est presque absente des discussions théoriques sur la conception logicielle, alors qu’en pratique on travaille toujours sous pression pour livrer rapidement du code. On n’a souvent pas le temps de faire les choses comme on voudrait ou de choisir la meilleure approche. Un bon logiciel est un logiciel qui résout des besoins réels des utilisateurs. Il existe des solutions de design qui conduisent plus souvent à des exécutions réussies, et le meilleur moyen de les trouver consiste à examiner en profondeur le code que j’écris réellement.
Que faudrait-il faire si la personne qui pose la question cherche des conseils externes parce qu’elle a l’impression que le logiciel de son équipe est mauvais ? Ou si c’est simplement un étudiant qui pose la question ?
Je n’avais jamais pensé que le temps nécessaire à l’implémentation pouvait aussi servir d’indicateur pour juger de la qualité d’un design, mais ça me paraît tout à fait pertinent. Moi aussi, j’apprends énormément à partir du codebase de mon équipe. Pour l’essentiel, j’y apprends ce qu’il y a de bon dans les excellents designs, et pour les parties moins réussies, j’apprends en continu en faisant mes propres recherches sur Google.
C’est un peu ancien maintenant, mais il existe la série « The Architecture of Open Source Applications », à laquelle ont contribué de nombreux responsables de projets open source, et elle est consultable gratuitement en ligne
https://aosabook.org/en/index.html
Cette question a déjà été posée plusieurs fois, donc je rassemble ici quelques liens utiles
Le code source de Yanderedev
Je ne suis probablement pas assez qualifié pour donner la bonne réponse, mais j’ai vraiment pris plaisir à lire, il y a environ 15 ans, un livre intitulé « Code Reading ». C’est exactement sur ce sujet
https://www.spinellis.gr/codereading/
Voir aussi la table des matières : https://www.spinellis.gr/codereading/toc.html
Il me semble qu’il existait aussi un autre livre au titre similaire, mais je ne m’en souviens plus précisément.
En pratique, un codebase contient souvent davantage d’implémentation que de design. Par exemple, on peut réécrire entièrement un système dans un autre langage tout en conservant le même design. Je recommande de s’exercer à rédiger des documents de design. Peu importe à quoi ils ressemblent, et il n’est pas nécessaire de se laisser enfermer par un template. Le plus important, c’est qu’une autre personne puisse prendre ce document et implémenter le système tel quel. Le document peut aussi servir de « trace de réflexion ». Il suffit d’y consigner clairement pourquoi une approche a été choisie, quelles autres alternatives existaient, et pourquoi elles n’ont pas été retenues. En reconnaissant et comparant les alternatives à l’avance, on montre au lecteur qu’on a réellement réfléchi au problème. Ce que fait un « bon » concepteur de systèmes, c’est examiner un espace de design plus large que les autres et y repérer de manière cohérente les bons points. Il suffit de choisir un problème, d’explorer différents espaces de design, puis d’expliquer pourquoi certains sont meilleurs que d’autres, en documentant le tout.
Il faut commencer par la question « quel est le problème que je veux résoudre ? ». Ensuite, trouver un codebase qui a résolu ce problème et analyser de près comment cela a été implémenté. Il faut garder à l’esprit qu’un bon design est étroitement lié à un contexte métier précis. Je pense que le principe du modèle interne de Wonham s’applique aussi au code. Par exemple, je voulais résoudre le problème des tests unitaires pour des cibles embarquées, donc j’ai analysé des projets open source liés au sujet et examiné de manière critique pourquoi chaque partie du code avait été écrite ainsi. En développant ma propre solution, et en revenant sans cesse à ces codebases, j’apprends de plus en plus à mesure que ma compréhension du domaine s’approfondit.
D’après mon expérience (30 ans dans le logiciel, 25 ans en architecture, master du MIT en architecture des systèmes), il n’existe pas vraiment de design « bon » dans l’absolu. Il existe clairement de mauvais designs, c’est-à-dire des conceptions qui mènent à de mauvais résultats, mais ce qui est « bon » dépend du contexte. Cela dépend de ce qu’on construit, des exigences en matière de sécurité ou de sûreté, et surtout de l’équipe qui implémente réellement le système ainsi que de sa structure. Une équipe composée uniquement de juniors peut mal interpréter un design sophistiqué et tout gâcher. Comme le dit la loi de Conway, la structure de l’équipe de développement se reflète directement dans le logiciel.
Une chose que j’ai clairement comprise en apprenant le software design, c’est qu’il n’existe pas de solution universelle. Ce serait agréable s’il y en avait une, mais devoir choisir la meilleure approche parmi des architectures et des paradigmes variés peut être frustrant. Cela dit, dès lors que les exigences sont bien prises en compte, le nombre d’options diminue déjà beaucoup. En ce moment, je travaille sur des systèmes embarqués où la sûreté est particulièrement critique, et cet environnement me pousse souvent à prendre des décisions que je n’utiliserais jamais dans d’autres contextes.
Au fond, l’essentiel est surtout d’éviter les compromis vraiment absurdes, et, avec une vision large, d’éviter aussi les pires choix. Ce que je ressens constamment sur le terrain, c’est que ce n’est pas tant une quête de la meilleure architecture qu’un combat permanent pour « éviter les décisions fondamentalement mauvaises ».
J’avais fait autrefois une petite liste de recommandations très simple, et elle reste valable
https://medium.com/@012parth/what-source-code-is-worth-studying-8755f88f8de5
Il y a un piège au milieu..
Le code source de Yanderedev... mdr