| name | code-quality |
| description | PERMANENT sur tout code source. Se charge dès qu'une écriture (Write/Edit) est envisagée sur un fichier de code : .js .ts .jsx .tsx .vue .svelte .astro .py .php .go .rs .java .kt .swift .rb .cs .c .cpp .dart .ex .elm .sql .sh .lua, ou tout fichier de logique applicative. Règles : STOP avant d'écrire, plan explicite attendant validation, principes Karpathy (ne pas deviner, code minimal, chirurgical, vérifier), zéro invention de référence (paths/fonctions/APIs jamais hallucinés), debugging 5 phases avec root-cause tracing, 3-strike rule, dead code et hardcoding detection, verification before completion, trace-test sur chaque ligne du diff. Ne se charge PAS quand : modifications limitées à .md, .json de config, TODO.md, CHANGELOG.md, DEV_TIME.md, ou contenu purement documentaire. |
Code Quality — Garde-fou permanent
Ce skill s'active automatiquement quand du code est écrit ou modifié, pour maintenir la qualité même sans commande explicite.
Tradeoff : ce garde-fou biaise vers la prudence et la vérification. Pour les tâches triviales (typo évidente, one-liner, renommage d'une variable locale), garder du jugement — pas besoin d'un plan formel ni d'une boucle de vérif complète. La règle STOP reste valable : on ne modifie un fichier qu'après instruction explicite ou feu vert.
STOP — Ne jamais coder sans validation
RÈGLE ABSOLUE : Ne PAS appeler Write, Edit ou créer/modifier de fichier tant que l'utilisateur n'a pas explicitement validé le plan.
Cette règle s'applique TOUJOURS — avec ou sans commande codebloom active. Aucune exception.
Comportement attendu
-
Question ("c'est possible ?", "on pourrait ?", "comment faire ?") → Répondre uniquement avec du texte. Aucun Write, aucun Edit, aucune modification — même si la réponse semble évidente à implémenter. Expliquer la faisabilité, les options, les tradeoffs. Attendre une instruction explicite ou un feu vert avant de toucher un fichier. Une question ne se transforme jamais en code sans passage par la case validation.
-
Instruction ("implémente X", "ajoute Y", "corrige Z") → Présenter le plan structuré, puis STOP :
**Plan :**
[1-3 phrases sur l'approche et le pourquoi]
**Fichiers :** [liste des fichiers touchés]
**Changements :** [action verb-first par fichier — "Ajouter...", "Modifier...", "Supprimer..."]
**Hors scope :** [ce qu'on ne touche PAS, si pertinent]
On y va ?
- Chaque action doit être atomique (un verbe, un fichier, un changement)
- Ne rien modifier tant que l'utilisateur n'a pas confirmé
-
Validation reçue ("oui", "go", "ok", "on y va", "fais-le") → Implémenter.
Pourquoi c'est non-négociable
Modifier un fichier sans validation part potentiellement dans la mauvaise direction — corriger après coûte plus cher que valider avant. L'utilisateur doit garder le contrôle à chaque étape.
Le plan d'abord, la validation ensuite, le code après.
Reformuler une tâche floue en objectif vérifiable
Une instruction vague mène à un code vague. Avant de coder, reformuler en objectif mesurable — une condition qu'un test ou une commande peut prouver comme satisfaite.
| Au lieu de... | Reformuler en... |
|---|
| "Ajoute de la validation" | "Écrire des tests pour les entrées invalides, puis les faire passer" |
| "Corrige le bug" | "Écrire un test qui reproduit le bug, puis le faire passer" |
| "Refactore X" | "S'assurer que les tests passent avant ET après" |
| "Rends ça plus rapide" | "Mesurer le temps actuel → définir une cible → vérifier l'écart" |
| "Nettoie le code" | "Lister les éléments morts précisément → supprimer ceux qui tracent à l'intention" |
| "Améliore l'UX" | "Nommer le parcours utilisateur cible → décrire l'état attendu après l'action" |
Critères de succès forts → la boucle peut s'auto-vérifier. Critères faibles ("fais marcher ça") → clarifications en cascade.
Plan multi-étapes — format step → verify
Pour une tâche qui se décompose en plusieurs étapes, utiliser le format couplé action / vérification — chaque étape doit porter sa propre preuve de réussite :
1. [Action atomique] → vérifier : [commande, test, ou observation qui prouve le résultat]
2. [Action atomique] → vérifier : [preuve]
3. [Action atomique] → vérifier : [preuve]
Exemple :
1. Ajouter middleware rate-limit en mémoire → vérifier : curl × 11 → 10 × 200, 1 × 429
2. Extraire en middleware global → vérifier : test hit /users et /posts, les deux limités
3. Brancher Redis pour multi-instance → vérifier : test 2 instances partagent le compteur
Chaque étape est indépendamment déployable et vérifiable. Si une étape échoue sa vérification → stop, on ne passe pas à la suivante.
Avant d'écrire du code
Checklist mentale
- Code réutilisable existant ? — Cherche dans le projet avant de créer
- Minimum de fichiers touchés ? — Ne modifie que ce qui est nécessaire
- CLAUDE.md lu ? — Conventions, patterns, architecture du projet
- DESIGN_SYSTEM.md lu ? — Si le changement touche à l'UI
Principes Karpathy (OBLIGATOIRES — toute violation bloque)
| Principe | En pratique |
|---|
| Ne pas deviner | Ambigu → demande. Deux approches possibles → montre les tradeoffs |
| Code minimal | Minimum viable. Pas d'abstractions prématurées. 10 lignes > 100 lignes si même résultat |
| Chirurgical | Ne touche que les fichiers concernés. Pas de refactoring opportuniste |
| Vérifier | Build/test après chaque changement significatif |
Exemples avant/après concrets pour chaque principe : voir reference/karpathy-examples.md. À consulter quand tu doutes ("est-ce que je suis en train d'overcomplexifier / de déborder / de supposer ?").
Pendant l'écriture
Ce qu'il faut faire
- Respecter les conventions de nommage du projet
- Suivre les patterns existants (imports, exports, structure)
- Garder la langue des commentaires cohérente avec le projet
- Écrire du code lisible — noms explicites, fonctions courtes
Ce qu'il faut éviter
- Ajouter du code "au cas où" ou "pour plus tard"
- Créer des abstractions pour un seul usage
- Ajouter des dépendances sans évaluation
- Laisser des
console.log, TODO ou code commenté
- Modifier du code hors du périmètre demandé
- Ajouter des types, docstrings ou commentaires au code non modifié
Pas de valeurs hardcodées
Les valeurs magiques rendent le code fragile et incohérent. Signaler systématiquement :
| Hardcodé | Mieux |
|---|
color: #3B82F6 | Variable/token (--color-primary, colors.primary) |
font-size: 14px | Token de typo (--text-sm, fontSize.sm) |
padding: 24px | Token de spacing (--space-6, spacing.lg) |
width: 1200px | Breakpoint nommé (--breakpoint-lg, screens.xl) |
z-index: 9999 | Échelle définie (--z-modal, zIndex.modal) |
timeout: 3000 | Constante nommée (API_TIMEOUT_MS) |
maxRetries: 3 | Constante nommée (MAX_RETRIES) |
"pending" / "active" | Enum ou constante (Status.PENDING, STATUS_ACTIVE) |
http://localhost:3000 | Variable d'env (process.env.API_URL) |
"sk-..." / "Bearer ..." | Variable d'env — jamais dans le code source |
Détection par langage
JavaScript / TypeScript :
- Strings répétées en 3+ endroits → constante ou enum
- URLs, ports, domaines dans le code → env var
- Valeurs numériques sans nom (
if (status === 3)) → constante nommée
process.env.X sans fallback ni validation → centraliser dans un config object
CSS / Tailwind :
- Couleurs hex brutes au lieu de tokens (
#3B82F6 vs var(--color-primary))
- Valeurs arbitraires répétées (
w-[347px], mt-[13px]) → token de spacing
z-index arbitraire → échelle fixe
Python :
- Strings répétées → constantes ou enum (
class Status(Enum))
magic numbers dans la logique métier → constantes nommées en UPPER_CASE
- Chemins de fichiers hardcodés →
pathlib + config
PHP :
- Strings SQL avec concaténation → requêtes préparées + constantes
- Chemins
include/require hardcodés → constantes ou autoload
En pratique
- UI → utiliser les tokens du design system (
DESIGN_SYSTEM.md) si existant — garantit la cohérence visuelle et facilite les changements globaux
- Config → constantes nommées en haut du fichier ou dans un fichier de config — un seul endroit à modifier
- Strings répétées → constantes ou enum — évite les typos et facilite le renommage
- Exception : valeurs évidentes (
0, 1, "", true/false) ou usages uniques clairement contextuels
Dead code — Détecter et nettoyer
Le code mort alourdit le projet, confond les développeurs et masque les vrais problèmes. Le signaler systématiquement.
Orphelins créés par ton diff vs dead code pré-existant
Distinction capitale :
| Origine | Action |
|---|
| Orphelins créés par TES changements (import inutilisé après suppression d'un appel, variable qui ne sert plus, fonction rendue obsolète par ton refactor) | Supprime immédiatement — tu dois laisser ta propre zone propre |
| Dead code pré-existant (fonction morte que tu croises, import orphelin qui existait déjà, variable commentée, fichier abandonné) | Signale, ne supprime pas — ce n'est pas ton périmètre. Mentionne-le à l'utilisateur, qu'il décide |
Pourquoi cette distinction : supprimer du dead code pré-existant pendant une autre tâche = drive-by deletion. Ça pollue le diff, masque l'intention du commit, et peut casser des usages cachés (reflection, config externe, plugins) que tu n'as pas vus. Ne supprime jamais ce que ton diff n'a pas rendu orphelin, sauf demande explicite.
Ce qui est du dead code
| Signal | Détection |
|---|
| Imports inutilisés | Module importé mais jamais référencé dans le fichier |
| Fonctions non appelées | Définies mais aucune référence dans le projet (grep le nom) |
| Variables assignées jamais lues | const x = ... sans aucune lecture de x |
| Branches impossibles | if (false), if (condition) où condition est toujours fausse |
| Code commenté | Blocs de code en commentaire — git garde l'historique |
| Fichiers orphelins | Fichier non importé/requis nulle part dans le projet |
| Feature flags périmés | Flag toujours true ou false en prod depuis longtemps |
| Dépendances fantômes | Package dans package.json/requirements.txt mais jamais importé |
| TODO/FIXME anciens | Marqueurs de plus de 3 mois sans activité |
| Routes/endpoints morts | Endpoint défini mais jamais appelé côté client |
Détection par langage
JavaScript / TypeScript :
- Linters :
eslint avec no-unused-vars, no-unused-imports
tsc --noUnusedLocals --noUnusedParameters
- Grep : fonctions exportées jamais importées ailleurs →
grep -r "functionName" --include="*.ts"
- Dépendances :
npx depcheck pour trouver les deps inutilisées
Python :
vulture pour détecter le code mort
pylint avec unused-import, unused-variable
pip-extra-reqs pour les deps fantômes
PHP :
phpstan détecte les variables et imports inutilisés
composer why package-name pour vérifier si une dep est utilisée
CSS :
- Classes CSS définies mais jamais utilisées dans le HTML/JSX
purgecss pour identifier les classes mortes
Ce qui n'est PAS du dead code (ne pas toucher)
- Code de tests/fixtures qui simule des cas d'usage
- Handlers d'événements référencés dans du HTML/config (pas visibles par grep)
- Exports d'une librairie/plugin (utilisés par les consommateurs, pas en interne)
- Code derrière un feature flag actif
- Interfaces/types utilisés uniquement pour la documentation ou le typage
Signaux de complexité
Signaler quand le code devient inutilement complexe :
| Signal | Mieux |
|---|
| Fonction > 5 paramètres | Objet config ou découpage |
| Nesting > 3 niveaux (if/for/if) | Early returns, extraction de fonctions |
| Fichier > 300 lignes | Découper par responsabilité |
| Switch/if-else > 5 branches | Table de lookup, map, ou polymorphisme |
| Booléen en paramètre | Probablement 2 fonctions distinctes |
| Fonction > 50 lignes | Extraire des sous-fonctions nommées |
Ne pas signaler la complexité nécessaire (algorithme intrinsèquement complexe). Signaler la complexité accidentelle (mauvaise structure).
Debugging — Investiguer avant de corriger
Quand un bug est signalé, ne pas deviner la cause — investiguer méthodiquement.
Règle absolue : PAS DE FIX SANS INVESTIGATION DE LA CAUSE RACINE.
Process en 5 phases
-
Collecter les preuves — Erreurs, stack traces, logs, git history récent, conditions exactes de reproduction. Collecter AVANT d'émettre une hypothèse. Root-cause tracing : tracer en arrière dans la call stack jusqu'à l'origine ("qu'est-ce qui a appelé cette fonction ? et avant ?"). Ne jamais fixer le symptôme sans remonter à la source.
-
Pattern matching — Classer le bug par catégorie connue :
| Pattern | Symptôme typique |
|---|
| Race condition | Marche parfois, échoue de façon non déterministe |
| Null propagation | Crash sur .property d'un objet qui devrait exister |
| State corruption | L'UI affiche un état impossible |
| Config drift | Marche en local, échoue en staging/prod |
| Stale cache | Les changements ne prennent pas effet |
| Integration failure | Fonctionne en isolation, échoue connecté |
-
Tester l'hypothèse — Confirmer avec des preuves AVANT de coder. Logging temporaire, assertions aux points suspects. Une seule variable à la fois — ne jamais tenter plusieurs corrections simultanées. 3-strike rule : 3 hypothèses échouées → escalader à l'utilisateur, stop guessing.
-
Corriger — Fix la cause racine, pas les symptômes. Defense-in-depth : valider aux 4 couches (entrée → logique métier → env → instrumentation debug) pour rendre le bug structurellement impossible. Correction minimale, pas de refactoring opportuniste. Max 5 fichiers touchés, sinon demander approval.
-
Vérifier — Écrire un test qui reproduit le bug AVANT le fix (RED), puis vérifier qu'il passe après (GREEN). Deux commits : test: reproduce [bug] puis fix: [bug].
Condition-based waiting (tests async)
Remplacer les sleep/délais arbitraires par du polling sur condition réelle. Un sleep(2000) est un aveu de ne pas savoir quand la condition est remplie — il est soit trop long (lent) soit trop court (flaky).
// MAL — délai arbitraire
await sleep(2000)
expect(result).toBeDefined()
// BIEN — polling sur condition
await waitFor(() => result !== undefined, { timeout: 5000, interval: 50 })
expect(result).toBeDefined()
Signaux d'alerte
- Bugs récurrents au même endroit → problème architectural, pas de malchance
- Fix qui crée des bugs en cascade → mauvaise couche modifiée
- "Ça devrait marcher maintenant" → inacceptable. Vérifier avec un test.
Si le bug semble lié à un pattern connu → recherche web (docs, GitHub Issues) pour confirmer le fix recommandé.
Pas sûr → le dire, proposer des hypothèses avec niveau de confiance.
Code smells — Signaux de mauvais design
Signaler quand le code présente des problèmes structurels :
| Smell | Symptôme | Mieux |
|---|
| Feature envy | Fonction qui utilise plus les données d'un autre module que les siennes | Déplacer la logique dans le bon module |
| God object | Classe/module qui fait tout | Découper par responsabilité |
| Primitive obsession | Strings/numbers là où un type/enum clarifierait | Type dédié ou enum |
| Long parameter list | > 4 paramètres | Objet config |
| Données mutables partagées | État mutable accessible par plusieurs modules | Immutabilité ou encapsulation |
| Blocs copiés-collés | Logique dupliquée en 3+ endroits | Extraire une fonction |
| Code commenté | Blocs de code en commentaire | Supprimer (git garde l'historique) |
Verification before completion
Règle : aucune affirmation de travail terminé sans preuve fraîche.
Avant de dire "c'est fait", "ça marche", "les tests passent" :
- Identifier la commande qui prouve le claim (test, build, lint...)
- Exécuter la commande — fraîche, complète
- Lire la sortie entière — exit code, nombre de failures
- Vérifier que la sortie confirme effectivement le claim
- Seulement alors affirmer le résultat avec la preuve
| Claim | Preuve requise | Insuffisant |
|---|
| Tests passent | Sortie test : 0 failures | Run précédent, "devrait passer" |
| Build OK | Build : exit 0 | Linter passe (≠ build) |
| Bug corrigé | Symptôme original reproduit → passe | "Code modifié" |
| Requirements OK | Checklist point par point | "Tests passent" seul |
Red flags linguistiques — ces mots trahissent un claim non vérifié :
- "devrait marcher", "probablement", "semble fonctionner"
- Satisfaction exprimée avant vérification ("Terminé !")
- "j'ai modifié le code, ça devrait être bon"
Anti-rationalisation
Ces excuses sont toutes invalides pour contourner les règles ci-dessus :
| Excuse | Réalité |
|---|
| "C'est trop simple pour tester" | Le code simple casse aussi. Le test prend 10 secondes. |
| "Je testerai après" | Un test écrit après passe immédiatement — il ne prouve rien |
| "J'ai testé manuellement" | Non reproductible, non automatisable, oublié demain |
| "C'est juste du refactoring" | Le refactoring casse des choses — c'est pour ça qu'on teste avant ET après |
| "Ça marchait avant mon changement" | Ton changement a peut-être cassé autre chose — vérifie |
| "Le fix est évident" | Les bugs les plus sournois ont des fix "évidents" qui masquent la vraie cause |
Après l'écriture
- Le code compile/build sans erreur ?
- Les tests existants passent toujours ?
- Le comportement est conforme à ce qui a été demandé ?
- Aucun fichier touché en dehors du périmètre ?
Déléguer aux agents (obligatoire)
Après chaque implémentation significative, lancer en parallèle en background :
- Agent
reviewer — review qualité, sécurité, footprint
- Agent
tester — générer et exécuter les tests
Si le code touche auth/secrets/inputs/crypto → lancer aussi security-auditor.
Avant d'implémenter une lib, un pattern ou une API inconnue → lancer researcher et attendre son résultat.
Ne pas attendre que l'utilisateur demande — les agents doivent se lancer automatiquement.
Protocole 3 strikes (erreurs et blocages)
Quand un build échoue, un test casse, ou une approche ne marche pas :
| Tentative | Action |
|---|
| Strike 1 | Analyser l'erreur, appliquer un fix ciblé |
| Strike 2 | Changer d'approche — la première ne marche pas |
| Strike 3 | Remettre en question les hypothèses de départ, rechercher plus largement |
| Après 3 strikes | STOP — escalader à l'utilisateur avec le détail des 3 tentatives et les erreurs exactes |
Ne jamais boucler sur la même erreur. Ne jamais retry sans changer quelque chose. Chaque tentative doit être différente de la précédente.
Circuit-breaker architectural
Si 3+ tentatives de fix échouent sur le même composant → ce n'est plus un bug isolé, c'est un problème d'architecture. Ne pas continuer à patcher. Signaler à l'utilisateur : "Ce composant résiste aux corrections ciblées — il a probablement besoin d'être restructuré. Voici les 3 tentatives et pourquoi elles ont échoué."
Error handling
Les erreurs mal gérées deviennent des bugs silencieux — l'application échoue sans trace, rendant le debug impossible. Signaler systématiquement :
Anti-patterns
// MAL — catch vide (erreur silencieuse)
try { await api.call() } catch (e) {}
// MAL — message générique inutile
catch (e) { throw new Error("Something went wrong") }
// MAL — log sans contexte
catch (e) { console.log(e) }
Pattern correct
// BIEN — gestion explicite avec contexte
try {
await api.call()
} catch (error) {
logger.error('API call failed', { endpoint, userId, error: error.message })
throw new AppError('SERVICE_UNAVAILABLE', 'External service is down')
}
Bonnes pratiques
- Pas de catch vide — un catch vide masque les erreurs et rend le debug impossible
- Erreurs typées/nommées plutôt que
throw new Error("fail") — permet de filtrer et traiter par type
- Distinguer erreurs attendues (validation, 404) et inattendues (crash, timeout) — pas le même traitement
- Logger avec contexte (qui, quoi, où) — un message d'erreur sans contexte ne sert à rien en production
- Fail fast — détecter tôt, remonter clairement. Un bug détecté tard coûte plus cher à corriger
- Erreurs async — un catch oublié sur une Promise peut crasher silencieusement le process
Pour l'aspect sécurité (ne pas exposer stack traces au client), voir la skill security.
Anti-patterns courants par langage
JavaScript / TypeScript
| Anti-pattern | Mieux |
|---|
any partout | Types explicites ou unknown + narrowing |
== null vs === null | Toujours === (sauf check null/undefined intentionnel) |
| Callback hell | async/await |
var | const par défaut, let si réassignation |
for (let i = 0; ...) sur un array | .map(), .filter(), .reduce() |
| Import de la lib entière | Import destructuré (import { get } from 'lodash') |
console.log pour debug | Supprimer avant commit |
Python
| Anti-pattern | Mieux |
|---|
except: (bare except) | except SpecificError: |
Mutable default args (def f(x=[])) | def f(x=None): x = x or [] |
import * | Imports explicites |
| String concatenation en boucle | f-strings ou join() |
| Pas de type hints | Type hints sur les signatures publiques |
PHP
| Anti-pattern | Mieux |
|---|
@ (error suppression) | Gestion explicite |
extract() | Accès explicite aux clés |
$$var (variables dynamiques) | Array associatif |
echo dans les classes | Return + template |
| Pas de strict types | declare(strict_types=1) |
Tool Boundaries
- Changements minimaux et ciblés — ne pas réécrire le code environnant
- Ne pas refactorer du code hors du périmètre demandé
- Ne pas migrer de librairie, framework ou pattern sauf demande explicite
- Appliquer les conventions dans le stack existant du projet
- Respecter le style existant, même si tu le ferais différemment — guillemets, indentation, pattern boolean, présence ou absence de type hints, langue des commentaires. Un diff qui change le style sans y être invité est un diff sale.
Trace-test — chaque ligne modifiée doit se justifier
Règle : chaque ligne qui apparaît dans un diff doit tracer directement à la demande utilisateur. Si une ligne ne peut pas s'expliquer par "ceci résout X, que l'utilisateur a explicitement demandé" → elle n'a rien à faire dans le diff.
Avant de finaliser un changement, relire le diff et poser sur chaque ligne modifiée :
"Pourquoi cette ligne est-elle ici ? L'utilisateur a-t-il demandé ça ?"
Si la réponse est "non mais c'était mieux", "au cas où", "tant qu'on y est", "pour la cohérence", ou "par habitude" → revert cette ligne. Ce sont des drive-by changes et ils sont interdits.
Cas typiques à revert :
- Ajouts de type hints / docstrings sur du code non demandé
- Changement de quotes (
' ↔ "), d'indentation, de formatting
- "Amélioration" d'une validation, d'un nom de variable, d'un commentaire adjacent
- Renommage d'une fonction qui n'est pas le sujet de la tâche
- Ajout d'erreur handling sur un chemin qui n'était pas dans la demande
Zéro invention — Ne jamais référencer ce qui n'a pas été vérifié
Règle absolue : ne jamais inventer un chemin de fichier, un nom de fonction, une API, un hook, un endpoint, un champ, un numéro de ligne, ou une version. Tout ce qui est cité dans une réponse, un plan, un diff, un commit, ou un rapport doit provenir d'une vérification réelle via outil (Read, Grep, Glob, Bash).
Pourquoi : les systèmes et humains en aval cassent sur les valeurs hallucinées. Un path inventé envoie l'utilisateur fouiller un fichier qui n'existe pas. Un nom de hook WordPress inventé compile mais ne se déclenche jamais. Une signature d'API hallucinée génère du code qui plante au runtime. Les LLMs sont brillants pour générer du plausible — c'est précisément ce qui rend l'hallucination dangereuse en code.
Ce qui doit être vérifié avant d'être cité
- Chemins de fichiers → confirmés par Glob ou Read
- Noms de fonctions, classes, variables, constantes → confirmés par Grep
- Signatures de fonctions → confirmées par Read du fichier source (paramètres, types, retours)
- APIs externes, méthodes de lib → confirmées par la doc officielle (WebFetch) ou le code installé dans
node_modules/vendor
- Hooks WordPress, filters, actions → confirmés par Grep dans core/plugins, pas par supposition
- Options de config, flags CLI → confirmés par
--help ou doc officielle
- Numéros de ligne → issus d'une Read récente, pas estimés
- Versions, dates, hashes → lus directement dans les fichiers manifest ou via git
En cas d'incertitude
- Préférer "à vérifier" à une affirmation fausse. Un rapport qui dit "je n'ai pas confirmé X" est utile. Un rapport qui affirme X faussement est un piège.
- Ne jamais "combler" un vide avec une valeur plausible pour paraître complet.
- Si un outil est nécessaire pour vérifier mais indisponible, le signaler ("à vérifier manuellement avec la commande Y").
Red flags linguistiques
Ces formulations trahissent souvent une invention :
- "Probablement dans
src/utils/..."
- "Il doit y avoir une fonction qui..."
- "L'API devrait accepter un paramètre..."
- "WordPress a un hook
..._filter pour ça"
Si tu te surprends à écrire une de ces phrases → stop, vérifie avec un outil avant de continuer.
Règle d'or
Trois lignes similaires valent mieux qu'une abstraction prématurée.
Le bon niveau de complexité, c'est le minimum nécessaire pour la tâche en cours.