La plupart des checklists de revue sont des placebos
Si votre équipe dispose d’une checklist pour le code review, il y a de fortes chances qu’elle se trouve sur une page wiki que personne n’ouvre. Elle dit probablement des choses comme „check for off-by-one errors” et „verify error handling.” Ce sont des affirmations vraies. Elles sont aussi trop vagues pour modifier le comportement.
Une checklist qui vous dit de faire „check for bugs” n’est pas une checklist. C’est un rappel que les bugs existent.
La checklist dans une Fagan inspection sert un objectif différent. Ce n’est pas une liste de choses dont il faut se préoccuper. C’est un outil structuré qui dirige l’attention du reviewer vers des catégories spécifiques de défauts qui ont été observées dans le codebase réel en cours de révision. Elle est construite à partir de données, adaptée au type d’artefact et utilisée pendant la préparation individuelle obligatoire. Lorsqu’elle est utilisée correctement, c’est l’une des principales raisons pour lesquelles une inspection structurée détecte trois à quatre fois plus de défauts qu’une revue informelle.
Ce qui rend une checklist „structurée”
Le mot „structurée” compte ici. Une checklist structurée n’est pas une checklist plus longue. C’est une checklist avec des propriétés de conception spécifiques.
Premièrement, elle est dérivée de données sur les défauts échappés. Les éléments proviennent de bugs qui ont réellement atteint la production, et non d’un document générique de bonnes pratiques. Si vos trois derniers incidents impliquaient tous des race conditions dans le async cleanup, cette catégorie obtient son propre élément de checklist. Si les null dereferences n’ont pas été un problème depuis deux ans, cet élément est supprimé.
Deuxièmement, elle est limitée au type d’artefact en cours de révision. Les Fagan inspections utilisaient à l’origine différentes checklists pour les documents d’exigences, les documents de conception, le source code et les plans de test. Chaque artefact a des catégories de défauts différentes. Une checklist de document de conception interroge la cohérence des interfaces et le couplage. Une checklist de source code interroge les boundary conditions et le nettoyage des ressources. Les mélanger dilue les deux.
Troisièmement, elle est utilisée pendant la préparation individuelle, pas pendant la réunion. Chaque inspector lit le matériel seul, avec la checklist, avant même que le groupe ne se réunisse. La checklist façonne ce que chaque personne voit lorsqu’elle lit le code de manière isolée. Ce n’est pas un document de référence partagé. C’est une lentille personnelle.
Quatrièmement, elle est suffisamment courte pour être utilisable. Une checklist avec quarante éléments est un catalogue, pas un outil. Fagan recommandait environ dix à quinze éléments par type d’artefact. La contrainte force la priorisation. Vous gardez les catégories qui comptent et vous écartez le bruit.
Comment en construire une à partir de vos propres données
La meilleure façon de construire une checklist structurée est d’examiner ce qui a déjà mal tourné. Voici un processus pratique.
Commencez par votre incident tracker, votre bug database ou vos notes de postmortem. Extrayez les vingt derniers défauts qui ont échappé à la révision et ont atteint la production ou les tests. Catégorisez chacun par root cause, pas par symptôme. „Page crashed” est un symptôme. „Missing null check after external API response” est une root cause.
Regroupez les root causes en catégories. Vous constaterez probablement que 80 pour cent de vos défauts échappés se répartissent en trois à cinq catégories. Ce sont vos éléments de checklist.
Pour chaque catégorie, rédigez une question déclencheuse spécifique, pas un rappel vague. „Check for nulls” est vague. „For every function that calls an external API, verify the response is validated before use” est une question déclencheuse. Elle indique exactement au reviewer ce qu’il doit chercher et où chercher.
Voici un exemple concret. Supposons que votre équipe déploie des services Python et que vous avez analysé les vingt derniers problèmes de production. Vous trouvez cette répartition :
- 6 problèmes : gestion d’erreurs manquante sur les appels externes
- 5 problèmes : limites de transaction de base de données incorrectes
- 4 problèmes : off-by-one dans la logique de pagination
- 3 problèmes : race conditions dans les données en cache
- 2 problèmes : journalisation de données sensibles
Votre checklist devrait comporter cinq éléments, un pour chaque catégorie. Chaque élément devrait être une question déclencheuse liée à vos patterns spécifiques.
#!/usr/bin/env python3
"""Build a structured review checklist from escaped defect data."""
from collections import Counter
from dataclasses import dataclass
from typing import List
@dataclass
class EscapedDefect:
id: str
root_cause: str
trigger_question: str
def build_checklist(defects: List[EscapedDefect], max_items: int = 10) -> List[str]:
"""Build a Fagan-style checklist from escaped defect data.
Groups by root cause, sorts by frequency, and returns trigger
questions for the top categories.
"""
counts = Counter(d.root_cause for d in defects)
top_causes = counts.most_common(max_items)
# Map root causes back to their most representative trigger question
cause_to_question = {}
for d in defects:
if d.root_cause not in cause_to_question:
cause_to_question[d.root_cause] = d.trigger_question
checklist = []
for cause, count in top_causes:
question = cause_to_question[cause]
checklist.append(f"[{count}x] {question}")
return checklist
# Example: escaped defects from a Python web service
DEFECTS = [
EscapedDefect("BUG-101", "missing-external-error-handling",
"For every external API call, is the response validated before use?"),
EscapedDefect("BUG-102", "missing-external-error-handling",
"For every external API call, is the response validated before use?"),
EscapedDefect("BUG-103", "missing-external-error-handling",
"For every external API call, is the response validated before use?"),
EscapedDefect("BUG-104", "transaction-boundary-error",
"Does every database write have the correct transaction scope?"),
EscapedDefect("BUG-105", "transaction-boundary-error",
"Does every database write have the correct transaction scope?"),
EscapedDefect("BUG-106", "pagination-off-by-one",
"For every pagination query, are the limit and offset tested at boundaries?"),
EscapedDefect("BUG-107", "cache-race-condition",
"For every cached value, is there a clear invalidation or TTL strategy?"),
EscapedDefect("BUG-108", "sensitive-data-in-logs",
"Does any log statement include user data, tokens, or PII?"),
]
if __name__ == "__main__":
checklist = build_checklist(DEFECTS, max_items=5)
print("Structured Review Checklist")
print("=" * 40)
for item in checklist:
print(f" [ ] {item}")
Exécutez ce script sur vos propres données de bugs et vous aurez une checklist liée à vos failure modes réels, pas à ceux de quelqu’un d’autre.
À quoi ressemble réellement la session de révision
Avec la checklist en main, la session de révision a un rythme spécifique.
Pendant la préparation individuelle, chaque inspector lit le matériel seul à environ 100 à 150 lignes par heure. Ils utilisent la checklist comme une lentille, pas comme un script. Ils ne parcourent pas la checklist élément par élément dans l’ordre. Ils lisent le code naturellement, et lorsqu’ils rencontrent un pattern qui correspond à une catégorie de la checklist, ils s’arrêtent et l’examinent attentivement.
La checklist ne remplace pas la lecture. C’est un pattern matcher pour des choses que votre cerveau est susceptible de sauter.
Dans l’inspection meeting, le reader paraphrase le code à voix haute. Lorsqu’un inspector repère un défaut potentiel, il le signale immédiatement. Les catégories de la checklist fournissent un vocabulaire partagé. Au lieu de dire „ça a l’air faux”, un inspector peut dire „ça ressemble à une erreur de limite de transaction, catégorie deux.” Le moderator le consigne. L’author écoute. Personne ne propose de correctif.
La checklist n’est pas consultée pendant la réunion. À ce stade, les inspectors l’ont déjà intériorisée. La réunion sert à recouper ce que chacun a trouvé de manière isolée.
Pourquoi les checklists génériques échouent
La plupart des équipes qui essaient les checklists abandonnent parce qu’elles utilisent le mauvais type.
Une checklist générique copiée d’un blog post n’a pas de poids émotionnel. Elle demande au reviewer de chercher des choses qui n’ont peut-être jamais eu lieu dans son codebase. Le reviewer la parcourt en diagonale, ne voit rien de familier et retourne à la lecture du diff comme il l’a toujours fait.
Une checklist structurée construite à partir de défauts échappés est différente. Chaque élément représente un incident réel qui a coûté du temps réel. Le reviewer connaît ces bugs parce qu’il a vu les postmortems. La checklist relie le comportement de révision à des échecs spécifiques et mémorables.
L’autre échec courant consiste à traiter la checklist comme un outil de réunion au lieu d’un outil de préparation. Si vous sortez la checklist pendant la réunion de révision, elle devient un script pour un survol de groupe. Tout le monde lit le même élément, regarde le même code et converge vers les mêmes observations évidentes. La force de la checklist réside dans la préparation individuelle, où six personnes appliquent les mêmes catégories indépendamment et trouvent des choses différentes.
La charge de maintenance que la plupart des équipes ignorent
Une checklist n’est pas un monument. C’est un document vivant qui se dégrade plus vite que le code.
Si vous ajoutez un élément à la checklist à chaque fois que quelque chose tourne mal mais que vous n’en retirez jamais un, vous aurez quarante éléments en six mois. À ce moment-là, les reviewers commencent à la traiter comme du papier peint.
Fagan recommandait de réviser la checklist elle-même après chaque quelques inspections. Retirez les éléments qui n’ont pas déclenché de constatation lors des cinq dernières révisions. Ajoutez des éléments uniquement pour de nouvelles catégories de défauts qui ont échappé à la production. Gardez le total en dessous de quinze. Si vous ne pouvez pas la garder courte, vous ne priorisez pas.
Voici un script léger pour élaguer une checklist basée sur des données historiques de constatations :
#!/usr/bin/env python3
"""Prune a review checklist: remove items that no longer trigger findings."""
from dataclasses import dataclass
from typing import List, Dict
@dataclass
class ChecklistItem:
category: str
trigger_question: str
findings_last_5_reviews: int
def prune_checklist(items: List[ChecklistItem], min_findings: int = 1) -> List[ChecklistItem]:
"""Remove checklist items that have not produced findings recently.
A Fagan-style checklist should be short enough to be usable.
Items that sit idle waste attention.
"""
kept = [item for item in items if item.findings_last_5_reviews >= min_findings]
removed = [item for item in items if item.findings_last_5_reviews < min_findings]
print(f"Kept {len(kept)} items, removed {len(removed)} items")
for item in removed:
print(f" REMOVED: [{item.category}] {item.trigger_question}")
return kept
# Example: current checklist with finding counts from the last 5 reviews
CURRENT_CHECKLIST = [
ChecklistItem("missing-external-error-handling",
"For every external API call, is the response validated before use?", 4),
ChecklistItem("transaction-boundary-error",
"Does every database write have the correct transaction scope?", 3),
ChecklistItem("pagination-off-by-one",
"For every pagination query, are the limit and offset tested at boundaries?", 0),
ChecklistItem("cache-race-condition",
"For every cached value, is there a clear invalidation or TTL strategy?", 1),
ChecklistItem("sensitive-data-in-logs",
"Does any log statement include user data, tokens, or PII?", 0),
]
if __name__ == "__main__":
pruned = prune_checklist(CURRENT_CHECKLIST, min_findings=1)
print("\nActive checklist:")
for item in pruned:
print(f" [ ] [{item.findings_last_5_reviews}x] {item.trigger_question}")
Planifiez cette révision trimestriellement. Une checklist obsolète est pire qu’aucune checklist car elle entraîne les reviewers à ignorer l’outil.
Le compromis : données vs. vitesse
Construire une checklist structurée à partir de données de défauts prend du temps. Vous avez besoin d’une catégorisation précise des incidents. Vous avez besoin de discipline pour garder la liste courte. Vous avez besoin d’un processus pour la maintenir à jour.
Une checklist générique prend cinq minutes à rédiger et cinq semaines à devenir irrelevante.
La version structurée est plus lente à créer mais plus rapide à utiliser. Un reviewer avec quinze questions déclencheuses ciblées scanne le code plus efficacement qu’un reviewer avec quarante rappels génériques. La spécificité fait gagner du temps.
Le coût réel est organisationnel. Vous avez besoin d’un registre de défauts échappés suffisamment détaillé pour en extraire les root causes. Beaucoup d’équipes ne l’ont pas. Leur bug tracker contient des titres comme „user report: page broken” et aucune analyse de suivi. Sans données de root cause, vous ne pouvez pas construire une checklist à partir de preuves. Vous ne pouvez que copier celle de quelqu’un d’autre.
Questions fréquemment posées
What is a structured checklist-based review?
Un processus de révision où chaque inspector utilise une checklist, construite à partir de données réelles de défauts échappés, pendant la préparation individuelle obligatoire avant une réunion d’inspection de groupe. La checklist contient des questions déclencheuses ciblées plutôt que des rappels génériques.
How is this different from a normal code review checklist?
Une checklist normale est souvent générique, copiée d’un modèle et consultée de manière occasionnelle pendant la révision. Une checklist structurée est dérivée de l’historique spécifique de défauts de votre équipe, limitée au type d’artefact et utilisée pendant une préparation individuelle concentrée à un rythme de lecture défini.
How many items should a structured checklist have?
Dix à quinze éléments par type d’artefact. Plus que cela et les reviewers commencent à survoler. Moins de cinq et vous manquez probablement des catégories.
How often should the checklist be updated?
Après chaque trois à cinq inspections, ou trimestriellement. Retirez les éléments qui n’ont pas produit de constatations. Ajoutez des éléments uniquement pour de nouvelles catégories de défauts échappés.
Can this work without a full Fagan inspection process?
Oui. La checklist elle-même est la partie la plus portable de la méthode Fagan. Exigez une préparation individuelle, donnez aux reviewers une checklist structurée construite à partir de vos données, et menez une réunion time-boxed avec un reader. Vous détecterez plus de défauts qu’avec une revue informelle, même sans la cérémonie complète en six phases.
Commencez par un module et un trimestre
Vous n’avez pas besoin de réformer tout votre processus de révision. Choisissez un module qui a eu des défauts en production au cours des six derniers mois. Rassemblez les root causes. Construisez une checklist de cinq éléments. Exigez que deux reviewers passent trente minutes avec le code et la checklist avant toute discussion de groupe.
Enregistrez ce qu’ils trouvent. Comparez-le avec ce que votre code review normal de pull request a détecté sur le même code. Cette seule comparaison vous dira si une checklist structurée vaut l’effort pour votre équipe.
Si les données disent oui, étendez-vous à un module supplémentaire. Si les données disent non, votre revue informelle est déjà assez bonne, ou vos données de défauts ne sont pas suffisamment détaillées pour construire une checklist utile. Dans les deux cas, vous avez une mesure réelle au lieu d’une opinion empruntée.