une-philosophie-de-la-conception-logicielle
Ce que ça fait
À utiliser lors de l'écriture, de la modification ou de la relecture de code chaque fois que le changement ajoute un nom exporté ou importable, crée un module, une classe, un composant, un helper, un hook, un service ou un wrapper, centralise du code répété, ou modifie une API. Règles d'Ousterhout (modules profonds, encapsulation de l'information, réduction de la complexité) plus le test invariant pour le partage de code, le test du coût pour le lecteur, et une note de conception obligatoire à la fin.
L'installation ouvre cette fiche dans votre application AgentsRoom. Si l'application n'est pas encore installée, vous serez redirigé vers la page de téléchargement.
SKILL.md
--- name: une-philosophie-de-la-conception-logicielle description: À utiliser lors de l'écriture, de la modification ou de la relecture de code chaque fois que le changement ajoute un nom exporté ou importable, crée un module, une classe, un composant, un helper, un hook, un service ou un wrapper, centralise du code répété, ou modifie une API. Règles d'Ousterhout (modules profonds, encapsulation de l'information, réduction de la complexité) plus le test invariant pour le partage de code, le test du coût pour le lecteur, et une note de conception obligatoire à la fin. --- # Une philosophie de la conception logicielle (John Ousterhout) ## Quand utiliser cette compétence Utilisez cette compétence lorsque vous concevez, écrivez, modifiez ou révisez du code. Elle s'applique à la conception de modules, aux modifications d'API, à la décomposition, au refactoring, aux noms, aux commentaires, aux tests et au travail sur la performance. Utilisez-la aussi lorsqu'un changement semble maladroit, ou lorsqu'un changement s'étend sur de nombreux fichiers. ## Le biais à corriger Un code fonctionnel n'est pas la même chose qu'un code simple. De petits morceaux, des motifs familiers, des indicateurs, des wrappers et une documentation supplémentaire peuvent rendre une conception plus complexe. Ils le font lorsqu'ils ajoutent à ce qu'un lecteur doit savoir, ou lorsqu'ils font fuiter des connaissances vers d'autres modules. ## Règles de décision - Mesurez une conception par la quantité de complexité qu'elle réduit. Préférez la conception qui allège la charge du lecteur. La complexité a quatre signes. Un changement nécessite des modifications à plusieurs endroits. Les dépendances sont cachées. Les étapes doivent se produire dans un ordre fixe. Le lecteur doit garder en tête de nombreux faits. - Traitez la conception comme un travail continu. Un premier patch qui fonctionne n'est pas terminé s'il rend les changements ultérieurs plus difficiles. Pour une décision concernant une interface, une division de module ou une abstraction, comparez deux ou plusieurs conceptions possibles. - Préférez les modules profonds. Un module profond a une interface petite et cache une grande quantité de complexité. Rejetez les services de passage, les wrappers de bibliothèque fins et les petits modules d'aide. Rejetez toute extraction qui ajoute des noms mais ne réduit pas la charge du lecteur. - Concevez une interface autour de ce que l'appelant doit savoir, pas autour de la façon dont l'implémentation fonctionne. Évitez les séquences d'initialisation fragiles, les indicateurs de mode, les boutons de configuration et les arguments qui montrent des choix internes. - Cachez les décisions qui peuvent changer. Les exemples sont les représentations internes, la forme de stockage, les protocoles, les formats de fichiers et les astuces de performance. La tenue des comptes, la normalisation et les cas limites sont d'autres exemples. Gardez chacun à l'intérieur du module qui possède la connaissance. - Faites descendre la complexité dans le module qui possède le détail. Acceptez une implémentation plus complexe lorsqu'elle offre aux appelants un contrat plus simple et supprime le travail répété à chaque point d'appel. - Rendez un module général au bon niveau. Ne faites pas correspondre un module à un seul appelant. N'ajoutez pas une abstraction vague pour des besoins futurs. Gardez les cas limites rares hors du chemin principal, et mettez le comportement spécial dans son propre endroit. - Joignez ou divisez les modules selon la complexité totale. Ne les joignez ou divisez pas selon la taille, l'ordre d'exécution du code, l'habitude ou l'apparence. Gardez ensemble l'état, le comportement, les règles et les décisions liés. Divisez-les seulement lorsque la nouvelle frontière est plus profonde et qu'un lecteur peut comprendre chaque côté seul. - Réduisez le nombre d'exceptions. Lorsque c'est possible, changez l'interface ou les règles pour que les états invalides ne puissent pas se produire. Ne faites pas répéter à chaque appelant le même code défensif. - Utilisez les commentaires pour réduire la complexité. Notez les contrats d'interface, les règles qui doivent rester vraies, les décisions de conception cachées et leurs raisons. Notez aussi les faits difficiles que les appelants ne doivent pas avoir à connaître. Ne répétez pas le code dans un commentaire. N'utilisez pas un commentaire pour cacher un mauvais nom, une mauvaise division ou un flux de contrôle confus. - Traitez les noms, la cohérence et la clarté comme des informations de conception. Un nom indique au lecteur l'abstraction, pas le mécanisme. Les opérations liées utilisent les mêmes conventions. Un code qui surprend le lecteur ajoute de la complexité, même s'il est court. - Écrivez des tests contre des contrats publics et des API stables. Testez la complexité cachée et les cas spéciaux à travers ces contrats. Ne laissez pas la facilité d'un test forcer une interface superficielle ou qui fuit. - Ajoutez un changement de performance, un motif, un paradigme ou un framework seulement pour une des deux raisons suivantes. Cela réduit la complexité dans cette base de code, ou les preuves montrent que le compromis est nécessaire. Cachez chaque optimisation derrière une interface stable. ## Signaux et réponses à chacun - Une fonctionnalité est maladroite, ou un changement s'étend sur plusieurs fichiers, ou un réviseur doit trouver des dépendances cachées. Réponse : cherchez un manque de masquage d'information et des modules superficiels. Cherchez aussi des étapes dans un ordre fixe, et de la complexité que les appelants portent. - Vous ajoutez un module, une couche, un service, un assistant, un wrapper ou une façade. Ou vous ajoutez un motif, une option, un callback ou un argument. Réponse : montrez qu'il cache plus de complexité qu'il n'en ajoute. - Vous modifiez une API. Réponse : vérifiez ce qu'un appelant normal doit savoir. Un appelant ne doit pas avoir besoin de l'ordre des appels, de la représentation ou du stockage. Un appelant ne doit pas avoir besoin du transport, du cache, du protocole ou du format de fichier. Un appelant ne doit pas avoir besoin du flux de travail interne ou de nombreuses étapes d'initialisation. - Vous ajoutez un cas spécial, un indicateur, un chemin d'exception, une condition ou un conteneur que les appelants peuvent voir. Réponse : demandez d'abord ce que le module propriétaire peut faire à la place. Il peut supprimer l'état invalide, isoler le comportement inhabituel ou donner une opération plus forte. - Vous divisez du code, extrayez une fonction ou ajoutez une variable. Réponse : vérifiez que la nouvelle frontière ou le nouveau nom porte du sens. Il ne doit pas seulement ajouter des sauts, un état qui passe, ou des étapes intermédiaires que les appelants peuvent voir. - Le code a des phases telles que `prepare`, `process` et `finalize`, ou les appelants doivent construire des objets en étapes. Réponse : vérifiez que l'ordre temporel est le vrai concept. Sinon, organisez le code autour de responsabilités stables. - Un nom est vague, nomme un mécanisme, n'est pas cohérent ou surprend le lecteur. Réponse : repensez la frontière d'abstraction. N'acceptez pas un nom qui est presque correct. - Un commentaire est long, répète le code, explique une interface confuse, ou montre des internes pour expliquer l'usage. Réponse : changez l'abstraction, ou déplacez le contrat manquant dans l'interface. - Vous optimisez la performance. Réponse : mesurez d'abord, puis cachez l'optimisation. Ne renoncez pas à la profondeur du module ou au masquage d'information sans preuve que le compromis est nécessaire. - Vous testez ou révisez. Réponse : regardez le comportement public et les contrats d'interface. Regardez aussi la complexité cachée derrière des API stables, et les cas spéciaux gardés derrière l'abstraction. ## Liste de contrôle finale - La modification réduit-elle l'effort pour comprendre, modifier, vérifier et étendre le système ? - Chaque élément d'interface, wrapper, couche, helper, option et nom cache-t-il suffisamment de complexité pour la justifier ? - Les décisions importantes sont-elles regroupées ? Les dépendances sont-elles visibles ? Les contraintes dont les appelants ont besoin sont-elles écrites ? Les parties internes susceptibles de changer sont-elles protégées ? - Les cas courants fonctionnent-ils sans étapes supplémentaires ? Les contrôles rares, cas spéciaux, astuces de performance et détails d'exception restent-ils hors du chemin commun ? - Les noms sont-ils précis et cohérents ? Les commentaires sont-ils à jour, sans répétition du code ? Le code suit-il les conventions existantes, sauf si de nouvelles informations justifient un changement ? ## Porte Utilisez la liste de contrôle complète lorsque la modification ajoute un nom que d'autres codes peuvent exporter ou importer. Utilisez-la également lorsque la modification crée un module, une classe, un composant, un helper, un hook, un service ou un wrapper, ou place du code répété en un seul endroit. Les renommages, codemods, changements de configuration, modifications de données et corrections d'une ligne ne nécessitent pas cette liste. ## Test d'invariant : ne partager que le code qui change ensemble - Extraire le code partagé uniquement lorsqu'il protège une règle que vous pouvez nommer. La preuve est la co-modification : l'historique montre que les copies ont été corrigées ou modifiées ensemble. Un code qui ne fait que sembler similaire et change indépendamment est une rime. Laissez les rimes comme duplicatas. Trois blocs similaires ne prouvent pas une règle. - Une correction doit supprimer le problème, pas le déplacer. Six castings regroupés dans un helper générique restent six castings. Écrivez le mapper typé que les castings cachaient. - Quand une abstraction est erronée, remettez le code en ligne et laissez la duplication revenir. Ne déformez pas l'abstraction avec des flags. - Ne divisez pas le code uniquement à cause de sa taille. Un module de 400 lignes qui cache une décision vaut mieux que quatre modules de 100 lignes qui fuient les mêmes jonctions. - Une lecture mécanique de Clean Code ou SOLID (fonctions très petites, une classe par responsabilité) donne des modules superficiels. Cette compétence prime sur cette pression. ## Coût pour le lecteur : le troisième test Le test de profondeur et le test d'invariant décident si une frontière doit exister. Le test du coût pour le lecteur décide si le code autour de la frontière est facile à modifier. Le lecteur suivant, une personne ou un agent, paie pour chaque ligne qu'il doit lire. Un agent paie en tokens. Un agent trouve le code par recherche textuelle, lectures partielles, vérification de type et tests. - **Trouvable.** Utilisez un seul nom pour chaque concept. Épelez-le de la même façon partout, pour que la recherche en texte clair le trouve. Défauts : noms construits à partir de chaînes, câblage via effets de bord d'import, deux noms pour un concept. Les chaînes de réexportation qui cachent la définition sont aussi des défauts. - **Arrêt précoce.** Mettez le contrat en haut du fichier ou au-dessus de l'export. Dites ce qu'il promet, ce qu'il cache et ce qu'il ne fait jamais. Ainsi, le lecteur peut s'arrêter tôt. - **Vérifiable par machine.** Utilisez des types exacts à l'entrée et à la sortie de chaque frontière, pour qu'une vérification de type remplace la lecture des appelants. Défauts : `any`, dictionnaires simples, flags booléens dont le sens n'est que dans le corps. - **Couplage visible.** Deux endroits doivent changer ensemble. Faites-le respecter avec un type partagé, un test ou une source unique. Si vous ne pouvez pas, marquez-le aux deux endroits. - **Pas de bruit.** Supprimez les commentaires qui répètent le code, et le code commenté. Supprimez les branches mortes et les commentaires qui enregistrent l'historique des changements. Supprimez un ancien chemin qui reste à côté de son remplacement. - **Prévisible.** Suivez la disposition existante du dépôt. Mettez le test là où un lecteur le cherche, et faites-le s'exécuter seul. La taille du fichier n'est pas dans cette liste exprès. Un fichier très volumineux est une raison de chercher une deuxième décision cachée. Ce n'est jamais une raison de couper le fichier. ## Sécurité Pour le code existant, écrivez d'abord un test qui maintient le comportement actuel. Puis rendez le module plus profond. Pour le nouveau code, écrivez le test qui définit le comportement prévu. ## Note de conception (obligatoire lorsque la porte s'applique) Lorsque la porte s'applique, mettez une section avec le titre `## Design note` dans la description de la pull request. Écrivez deux à quatre lignes : - Chaque frontière que vous avez ajoutée, et la décision qu'elle cache. - Chaque duplication que vous avez gardée volontairement, et la raison. - Chaque partie superficielle que vous avez acceptée, et la raison. Si la porte ne s'applique pas, écrivez `## Design note` suivi de `Gate not applicable: <reason>`. Mettez aussi la note de conception dans le résumé de votre étape finale. ## Mode revue Utilisez cette section lorsque vous révisez ou testez du code écrit par un autre agent ou une autre personne. 1. Vérifiez la note de conception. Quand la porte s'applique et que la pull request n'a pas de section `## Design note`, signalez un problème bloquant. Quand la note ne correspond pas au diff, signalez un problème bloquant. 2. Un problème de conception est bloquant uniquement s'il remplit les deux conditions : - Il nomme une règle de cette compétence. La règle est une règle de décision, la porte, le test d'invariant ou un élément du coût pour le lecteur. - Il indique un coût concret pour le lecteur ou pour le changement suivant. Exemples : « Les appelants doivent connaître la forme du stockage. » « Un concept a deux noms. » « Un changement de cap nécessite des modifications dans trois fichiers. » 3. Marquez toute autre observation de conception comme non bloquante. Mettez-la dans une liste séparée intitulée « Notes de conception non bloquantes ». Une note non bloquante ne renvoie jamais le travail au constructeur. 4. Ne signalez pas une préférence comme un problème. Un nom différent, une disposition de fichier ou un style est une préférence. Cela devient un problème seulement s'il enfreint une règle nommée et a un coût concret. 5. Quand le même problème de conception revient lors d'un second cycle de revue, escaladez-le. Ne demandez pas le même changement une troisième fois. ## Compétences associées (lorsqu'elles sont installées) - `find-shared-code` : une recherche en mode rapport uniquement de l'historique récent pour du code qui mérite d'être partagé. Elle utilise le test d'invariant et le test de profondeur de cette compétence. - `refactoring` et `working-effectively-with-legacy-code` : les étapes sûres vers une conception plus profonde. Cette compétence décide si une nouvelle frontière reste. ## Source et licence Cette compétence s'appuie sur les règles "mini" de A Philosophy of Software Design dans le dépôt ciembor/agent-rules-books sur GitHub (licence MIT, commit 893a88a). La porte, le test d'invariant, le test du coût pour le lecteur, la note de conception et le mode revue sont des ajouts à ces règles. Le dépôt contient également les règles complètes du livre.
Tags
Pour aller plus loin
Claude Ads : le skill Claude Code qui audite tes comptes publicitaires
Claude Ads est un skill open source pour Claude Code : plus de 250 vérifications sur Google, Meta, LinkedIn, TikTok ou Amazon Ads, un score sur 100 et un plan d'action priorisé, en une dizaine de minutes. Installation, commandes, limites, et comment l'orchestrer dans AgentsRoom.
AGENTS.md : un seul fichier de contexte pour tous tes agents de code (Codex, Antigravity, Claude)
AGENTS.md, c'est le fichier d'instructions portable que tes agents de code lisent avant de toucher à ton code. Ce qu'il faut y mettre, en quoi il diffère de CLAUDE.md, et comment garder un seul contexte entre Codex, Antigravity et Claude.
Télécharger AgentsRoom
Lancez tous vos agents IA, sur tous vos projets, depuis une seule fenêtre.
App companion : suivez vos agents en déplacement
Utilisez Claude, Codex, Antigravity CLI ou un autre fournisseur IA.
Remontez bugs et demandes directement dans votre backlog public.