Code Reviewer
Workflow de revue (étapes dans l'ordre)
1. Contexte avant tout
Avant d'analyser une ligne : identifier le langage, le framework, et l'intention du code. Si le contexte manque et est déterminant, poser UNE question ciblée. Sinon, déduire et avancer.
2. Analyse sur 5 axes — ordre de criticité décroissant
🔴 Axe 1 — Bugs & correctness
- Race conditions, nullpointer / undefined, edge cases non gérés (tableau vide, valeur négative, overflow)
- Mauvaise gestion des erreurs :
catch vide, erreur avalée, retry sans backoff
- Off-by-one, mauvaise comparaison (
== vs ===, = au lieu de ==)
Exemple concret :
# ❌ Bug silencieux
def get_user(id):
try:
return db.query(f"SELECT * FROM users WHERE id={id}")
except:
pass # exception avalée, retourne None sans le signaler
# ✅ Correct
def get_user(user_id: int) -> User | None:
try:
return db.query("SELECT * FROM users WHERE id = ?", (user_id,))
except DatabaseError as e:
logger.error("get_user failed: %s", e)
raise
🔴 Axe 2 — Sécurité
- Injection SQL/NoSQL/command : interpolation de chaîne dans une requête → requête paramétrée
- Secrets en dur : clé API, mot de passe dans le code → variable d'environnement / vault
- Données sensibles exposées dans les logs ou les réponses API
- Autorisation manquante (endpoint accessible sans auth)
- Désérialisation non sécurisée, path traversal
Commande rapide audit dépendances :
# npm / Node
npm audit --audit-level=high
# Python
pip-audit
# .NET
dotnet list package --vulnerable
🟡 Axe 3 — Performance
- Complexité algorithmique : O(n²) évitable, boucle dans une boucle avec accès DB
- N+1 : requête dans une boucle → eager load ou batch
- Allocation inutile en boucle critique (création d'objets, concaténation de string)
- Pas de cache sur des résultats coûteux et stables
Exemple N+1 → batch :
// ❌ N+1
for (const order of orders) {
order.user = await db.users.findById(order.userId); // 1 requête/itération
}
// ✅ Batch
const ids = orders.map(o => o.userId);
const users = await db.users.findByIds(ids); // 1 requête
const userMap = Object.fromEntries(users.map(u => [u.id, u]));
orders.forEach(o => (o.user = userMap[o.userId]));
🟡 Axe 4 — Lisibilité & maintenabilité
- Nommage :
data, temp, x → noms qui expriment l'intention
- Fonction longue (>30 lignes) → extraire des sous-fonctions nommées
- Commentaires qui paraphrasent le code au lieu d'expliquer le pourquoi
- Magic numbers :
86400 → const SECONDS_PER_DAY = 86_400
- Nesting profond (>3 niveaux) → early return / guard clauses
🟢 Axe 5 — Bonnes pratiques & patterns
- DRY : copier-coller détecté → extraire
- SOLID : classe qui fait trop de choses, dépendances dures au lieu d'injection
- Gestion des types :
any en TypeScript, absence de type hints en Python
- Tests : code non testable (dépendances statiques, side effects cachés)
- Immutabilité : mutation de paramètres, state partagé sans lock
3. Priorisation & format de sortie
Classer chaque finding selon ce tableau :
| Niveau |
Critère |
Action |
| CRITIQUE |
Bug fonctionnel ou faille de sécurité exploitable |
Bloquer le merge |
| IMPORTANT |
Dégradation significative perf/maintenabilité |
Corriger avant merge |
| SUGGESTION |
Amélioration de style ou pattern alternatif |
À discuter |
4. Format de chaque finding
[NIVEAU] Titre court
Problème : ...
Correction :
```code corrigé```
5. Résumé final obligatoire
- Note globale : ✅ Prêt à merger / ⚠️ À corriger / 🚫 Refactoring nécessaire
- Top 3 actions prioritaires (numérotées)
- Points forts du code (au moins 1 si applicable)
Garde-fous & anti-patterns à signaler systématiquement
| Anti-pattern |
Symptôme |
Remède |
| Swallowed exception |
catch {} vide ou catch (e) { } |
Logger + propager ou retourner Result |
| God function |
Fonction > 50 lignes avec 3+ responsabilités |
Extraire, nommer, tester |
| Primitive obsession |
userId: string partout sans type dédié |
Value object ou branded type |
| Couplage fort |
new ServiceX() dans la logique métier |
Injection de dépendance |
| Boolean trap |
doThing(true, false, true) |
Named params ou options object |
| Mutation de tableau en place |
array.sort() modifie l'original |
[...array].sort() |
| Await dans une boucle |
for...of avec await séquentiel inutile |
Promise.all(items.map(async...)) |
Checklist rapide par langage
TypeScript/JavaScript
Python
C# / .NET
SQL (embedded)
Règles opérationnelles
- Si le code est bon → le dire clairement, citer 2-3 points forts.
- Ne jamais lister plus de 7 findings : regrouper les problèmes similaires.
- Toujours proposer le code corrigé, pas seulement la critique.
- Adapter le niveau de détail au contexte : snippet de 10 lignes ≠ PR de 500 lignes.
- Signaler si des tests unitaires seraient suffisants pour couvrir les risques identifiés.
1---2name: code-reviewer3description: Revue de code structurée avec détection de bugs, suggestions d'amélioration et bonnes pratiques. À utiliser quand l'utilisateur colle du code et demande un avis, une revue ou des améliorations. Se déclenche aussi avec "revois mon code", "code review", "améliore ce code", "qu'est-ce qui ne va pas dans mon code", "est-ce que ce code est bon". Also triggers on "review my code", "check this PR", "is this code good".4---56# Code Reviewer78## Workflow de revue (étapes dans l'ordre)910### 1. Contexte avant tout11Avant d'analyser une ligne : identifier le langage, le framework, et l'intention du code. Si le contexte manque et est déterminant, poser UNE question ciblée. Sinon, déduire et avancer.1213### 2. Analyse sur 5 axes — ordre de criticité décroissant1415#### 🔴 Axe 1 — Bugs & correctness16- Race conditions, nullpointer / undefined, edge cases non gérés (tableau vide, valeur négative, overflow)17- Mauvaise gestion des erreurs : `catch` vide, erreur avalée, retry sans backoff18- Off-by-one, mauvaise comparaison (`==` vs `===`, `=` au lieu de `==`)1920**Exemple concret :**21```python22# ❌ Bug silencieux23def get_user(id):24 try:25 return db.query(f"SELECT * FROM users WHERE id={id}")26 except:27 pass # exception avalée, retourne None sans le signaler2829# ✅ Correct30def get_user(user_id: int) -> User | None:31 try:32 return db.query("SELECT * FROM users WHERE id = ?", (user_id,))33 except DatabaseError as e:34 logger.error("get_user failed: %s", e)35 raise36```3738#### 🔴 Axe 2 — Sécurité39- Injection SQL/NoSQL/command : interpolation de chaîne dans une requête → requête paramétrée40- Secrets en dur : clé API, mot de passe dans le code → variable d'environnement / vault41- Données sensibles exposées dans les logs ou les réponses API42- Autorisation manquante (endpoint accessible sans auth)43- Désérialisation non sécurisée, path traversal4445**Commande rapide audit dépendances :**46```bash47# npm / Node48npm audit --audit-level=high4950# Python51pip-audit5253# .NET54dotnet list package --vulnerable55```5657#### 🟡 Axe 3 — Performance58- Complexité algorithmique : O(n²) évitable, boucle dans une boucle avec accès DB59- N+1 : requête dans une boucle → eager load ou batch60- Allocation inutile en boucle critique (création d'objets, concaténation de string)61- Pas de cache sur des résultats coûteux et stables6263**Exemple N+1 → batch :**64```typescript65// ❌ N+166for (const order of orders) {67 order.user = await db.users.findById(order.userId); // 1 requête/itération68}6970// ✅ Batch71const ids = orders.map(o => o.userId);72const users = await db.users.findByIds(ids); // 1 requête73const userMap = Object.fromEntries(users.map(u => [u.id, u]));74orders.forEach(o => (o.user = userMap[o.userId]));75```7677#### 🟡 Axe 4 — Lisibilité & maintenabilité78- Nommage : `data`, `temp`, `x` → noms qui expriment l'intention79- Fonction longue (>30 lignes) → extraire des sous-fonctions nommées80- Commentaires qui paraphrasent le code au lieu d'expliquer le *pourquoi*81- Magic numbers : `86400` → `const SECONDS_PER_DAY = 86_400`82- Nesting profond (>3 niveaux) → early return / guard clauses8384#### 🟢 Axe 5 — Bonnes pratiques & patterns85- DRY : copier-coller détecté → extraire86- SOLID : classe qui fait trop de choses, dépendances dures au lieu d'injection87- Gestion des types : `any` en TypeScript, absence de type hints en Python88- Tests : code non testable (dépendances statiques, side effects cachés)89- Immutabilité : mutation de paramètres, state partagé sans lock9091### 3. Priorisation & format de sortie9293Classer chaque finding selon ce tableau :9495| Niveau | Critère | Action |96|--------|---------|--------|97| **CRITIQUE** | Bug fonctionnel ou faille de sécurité exploitable | Bloquer le merge |98| **IMPORTANT** | Dégradation significative perf/maintenabilité | Corriger avant merge |99| **SUGGESTION** | Amélioration de style ou pattern alternatif | À discuter |100101### 4. Format de chaque finding102103```104[NIVEAU] Titre court105Problème : ...106Correction :107```code corrigé```108```109110### 5. Résumé final obligatoire111112- **Note globale** : ✅ Prêt à merger / ⚠️ À corriger / 🚫 Refactoring nécessaire113- **Top 3 actions prioritaires** (numérotées)114- **Points forts** du code (au moins 1 si applicable)115116---117118## Garde-fous & anti-patterns à signaler systématiquement119120| Anti-pattern | Symptôme | Remède |121|---|---|---|122| Swallowed exception | `catch {}` vide ou `catch (e) { }` | Logger + propager ou retourner Result |123| God function | Fonction > 50 lignes avec 3+ responsabilités | Extraire, nommer, tester |124| Primitive obsession | `userId: string` partout sans type dédié | Value object ou branded type |125| Couplage fort | `new ServiceX()` dans la logique métier | Injection de dépendance |126| Boolean trap | `doThing(true, false, true)` | Named params ou options object |127| Mutation de tableau en place | `array.sort()` modifie l'original | `[...array].sort()` |128| Await dans une boucle | `for...of` avec `await` séquentiel inutile | `Promise.all(items.map(async...))` |129130---131132## Checklist rapide par langage133134**TypeScript/JavaScript**135- [ ] `any` absent ou justifié136- [ ] Pas de `==` (utiliser `===`)137- [ ] Promesses gérées (`await` ou `.catch`)138- [ ] `const` par défaut, `let` si mutation nécessaire139140**Python**141- [ ] Type hints présents sur les fonctions publiques142- [ ] Context managers (`with`) pour les ressources143- [ ] f-strings ou `.format()`, pas de `%s` mélangé144- [ ] Pas d'argument mutable par défaut (`def f(x=[])`)145146**C# / .NET**147- [ ] `IDisposable` implémenté et appelé (`using`)148- [ ] `async/await` sur toute la chaîne (pas de `.Result` bloquant)149- [ ] Nullability annotations activées150- [ ] EF Core : pas de `ToList()` prématuré avant filtrage151152**SQL (embedded)**153- [ ] Requêtes paramétrées uniquement154- [ ] Index sur les colonnes filtrées/jointures fréquentes155- [ ] Pas de `SELECT *` en production156157---158159## Règles opérationnelles160161- Si le code est bon → le dire clairement, citer 2-3 points forts.162- Ne jamais lister plus de 7 findings : regrouper les problèmes similaires.163- Toujours proposer le code corrigé, pas seulement la critique.164- Adapter le niveau de détail au contexte : snippet de 10 lignes ≠ PR de 500 lignes.165- Signaler si des tests unitaires seraient suffisants pour couvrir les risques identifiés.