Deux relecteurs, un diff, zéro chevauchement

Deux ingénieurs seniors relisent le même pull request. L’un signale un null check manquant. L’autre repère une race condition dans le cleanup path. Aucun des deux ne trouve les deux.

Si vous n’aviez désigné qu’un seul relecteur, l’un de ces bugs aurait été livré. Ce n’est pas un écart de compétences. C’est une propriété prévisible de l’attention humaine, et Michael Fagan l’a documentée chez IBM en 1976.

Fagan mesurait les taux de détection de défauts dans le pipeline logiciel d’IBM. Ses données révélaient quelque chose d’inconfortable : même les inspecteurs expérimentés ne détectaient qu’une fraction des défauts totaux que le groupe finissait par trouver. La vraie valeur ne résidait pas dans l’expertise d’une seule personne. Elle résidait dans la combinaison structurée de multiples perspectives.

La plupart des équipes ne structurent pas cette combinaison aujourd’hui. Un ingénieur senior survole un diff entre deux réunions, remarque un problème de style, approuve et passe à autre chose. Le relecteur suivant fait de même. Tous deux manquent l’erreur off-by-one qui corrompt les données de production mardi prochain.

Fagan a appelé cela le syndrome de la relecture non structurée. Le groupe a des yeux, mais pas de processus.

Ce qu’est réellement une Fagan Inspection

Une Fagan Inspection n’est pas une réunion où des gens lisent du code ensemble et partagent leurs sentiments. C’est un processus formel avec des rôles définis, des critères d’entrée et un output mesurable. Fagan l’a conçu parce que les relectures non structurées gaspillaient du temps et laissaient fuir des défauts à peu près au même rythme que l’absence totale de relecture.

L’idée centrale est la séparation des rôles. Chacun a exactement un travail :

  • Le moderator dirige la réunion et fait respecter les règles. Il n’inspecte pas.
  • Le reader paraphrase le code à voix haute. Cela oblige le groupe à confronter ce que le code fait réellement, et non ce que l’author avait l’intention de faire.
  • Le tester réfléchit aux execution paths, aux boundary conditions et aux coverage gaps.
  • L’author répond aux questions mais ne défend pas le code.

Cette séparation empêche le failure mode le plus courant de la relecture de groupe : l’author qui convainc tout le monde de passer outre ses préoccupations.

Quand l’author est aussi celui qui explique, il lisse les ambiguïtés. « Oh, cette variable est toujours définie par le caller. » Le groupe hoche la tête. Personne ne vérifie. Le rôle de reader existe pour briser cette habitude. Si le reader ne peut pas paraphraser une fonction en une phrase, la fonction n’est pas prête à être livrée.

Pourquoi les checklists battent l’intuition

Fagan a également introduit des inspection checklists. Ce ne sont pas des coding standards génériques copiés d’un style guide. Elles sont adaptées au type spécifique d’artefact en cours de relecture.

Une checklist pour une state machine demande : avez-vous traité chaque transition ? Une checklist pour un resource allocator demande : chaque allocation est-elle appariée avec une deallocation sur chaque path ?

La checklist existe parce que l’attention humaine est inégale. Un expert qui a écrit dix mille requêtes de base de données va mentalement sauter le bloc BEGIN TRANSACTION. Son cerveau l’autocomplete comme correct. Fagan a découvert que les inspecteurs guidés par des checklists trouvaient des défauts que les relecteurs guidés par l’intuition laissaient passer, non parce que les experts étaient négligents, mais parce que l’expertise crée des blind spots.

Voici une checklist lightweight pour une seule fonction Python :

CHECKLIST = [
    "Can a non-author paraphrase what this function does in one sentence?",
    "Does every execution path return or raise predictably?",
    "What happens at the minimum and maximum valid inputs?",
    "What happens at exactly one step past the boundary?",
    "Does the function mutate any argument, closure, or global state?",
    "Is every resource acquired also released on the error path?",
    "If this raises, can the caller distinguish recoverable from fatal?",
]

Ce n’est pas de la bureaucratie. C’est une forcing function pour une attention systématique.

Fagan a divisé les inspections en quatre phases, et la réunion est la plus courte

Une véritable Fagan Inspection comporte quatre phases, et la réunion elle-même est la plus courte.

Preparation. Chaque inspecteur relit le matériel seul, avec la checklist, avant que le groupe ne se réunisse. Fagan a découvert que les inspecteurs préparés trouvaient environ deux fois plus de défauts que ceux qui arrivaient à froid. La réunion existe uniquement pour combiner les findings, pas pour les générer.

La réunion. Le reader parcourt le code. Le tester pose des questions de type qu’arriverait-il si. Le moderator maintient la durée sous deux heures. L’author prend des notes. Personne ne corrige de code pendant la réunion. Les défauts sont enregistrés et le groupe passe à la suite.

Rework. L’author corrige seul les défauts enregistrés.

Follow-up. Le moderator vérifie que chaque défaut a été traité. Des rework importants peuvent déclencher une seconde inspection.

Cette structure semble lourde pour un pull request moderne. Fagan l’a conçue pour du software mainframe où un seul défaut pouvait coûter des millions. Les principiels s’adaptent toutefois encore à des contextes plus petits.

Où cela devient excessif

Les Fagan Inspections ne sont pas gratuites. Le temps de preparation à lui seul ajoute une surcharge significative. Pour un bugfix de dix lignes, une Fagan Inspection complète est absurde. Vous n’avez pas besoin de quatre personnes et d’une checklist pour détecter un import manquant.

La courbe de payoff n’est pas linéaire. Les données de Fagan suggéraient que les inspections étaient les plus rentables pour les modules complexes et à haut risque : state machines, parsers, resource managers, tout ce qui implique du non-local state ou des ordering constraints subtils. Pour les handlers CRUD et les tests boilerplate, une relecture informelle suffit.

La vraie erreur consiste à appliquer la même stratégie de relecture à chaque changement. Une faute de frappe dans un message de log n’a pas besoin d’une Fagan Inspection. Un distributed transaction coordinator en a probablement besoin.

Une version lightweight utilisable dès aujourd’hui

Vous n’avez pas besoin de la culture de réunion d’IBM pour en tirer la majeure partie du bénéfice. Voici une adaptation lightweight qui fonctionne pour les équipes modernes :

  1. Exiger une relecture individuelle avant la discussion de groupe. Chaque relecteur soumet des commentaires écrits avant que quiconque ne parle. Cela empêche la première opinion bruyante de dominer.

  2. Faire tourner le rôle de reader. Demander à un relecteur de résumer le changement en ses propres termes avant que quiconque ne le critique. S’il ne peut pas, le changement est trop grand ou trop confus.

  3. Construire une checklist d’équipe. Commencer avec les sept questions ci-dessus. Ajouter des items spécifiques au domaine. La réviser trimestriellement.

  4. Séparer l’author et le défenseur. L’author répond aux questions factuelles. Il ne soutient pas que le code est correct. Si un relecteur est confus, c’est une donnée, pas un débat.

  5. Enregistrer les défauts, les corriger plus tard. Ne réécrivez pas de code pendant la relecture. Enregistrez l’issue, terminez, puis corrigez.

Voici un script simple pour générer une review checklist pour n’importe quel module Python :

import ast
import sys
from pathlib import Path

def generate_checklist(source_path: str) -> list[str]:
    """Generate a Fagan-style checklist from a Python module."""
    source = Path(source_path).read_text()
    tree = ast.parse(source)

    checklist = [
        f"Module {Path(source_path).name}: {len(tree.body)} top-level statements",
        "Can a non-author state the module's responsibility in one sentence?",
    ]

    for node in ast.walk(tree):
        if isinstance(node, ast.FunctionDef):
            checklist.append(
                f"Function '{node.name}': does every path return or raise?"
            )
            if any(isinstance(n, ast.Try) for n in ast.walk(node)):
                checklist.append(
                    f"Function '{node.name}': is every exception handled explicitly?"
                )

    return checklist

if __name__ == "__main__":
    for item in generate_checklist(sys.argv[1]):
        print(f"[ ] {item}")

Exécutez-le comme ceci :

python inspection_checklist.py src/transaction.py

Il ne trouvera pas vos bugs. Il vous force à regarder aux bons endroits.

Embaucher des gens plus intelligents ne résoudra pas un problème de processus

La recherche de Fagan a presque cinquante ans, mais la conclusion n’a pas changé. Les relecteurs individuels sont inconsistants. Les groupes le sont aussi, à moins de les structurer. La variance entre relecteurs n’est pas un problème à éliminer. C’est une ressource à organiser.

La prochaine fois qu’un relecteur trouve un bug qu’un autre a manqué, ne demandez pas qui est meilleur. Demandez si votre processus est suffisamment structuré pour combiner ce que tous deux voient. Fagan a déjà essayé de s’en sortir par le recrutement. Ça ne marche pas.

FAQ

Qu’est-ce qu’une Fagan Inspection ?

Une Fagan Inspection est un processus formel et structuré de code review développé par Michael Fagan chez IBM en 1976. Il utilise des rôles définis (moderator, reader, tester, author), des exigences de preparation et des checklists pour maximiser la détection de défauts dans les artefacts logiciels.

Pourquoi différents relecteurs trouvent-ils différents bugs ?

L’attention humaine est sélective. Les experts développent des raccourcis mentaux qui leur permettent de lire du code rapidement, mais ces mêmes raccourcis créent des blind spots. Différents relecteurs ont différents backgrounds et patterns cognitifs, donc leurs blind spots ne se chevauchent pas parfaitement. La recherche de Fagan a montré que la valeur de l’inspection réside dans la combinaison de multiples perspectives incomplètes, et non dans la recherche d’un relecteur parfait.

Les Fagan Inspections sont-elles encore utilisées aujourd’hui ?

Le processus formel complet est rare en dehors des industries critiques pour la sécurité comme l’aérospatial et les dispositifs médicaux. Cependant, les principes sous-jacents — preparation individuelle, séparation des rôles et relecture guidée par des checklists — sont de plus en plus adaptés par les équipes software high-performing. Les idées centrales ont également influencé les pratiques modernes comme les structured walkthroughs et les formal technical reviews.

Quand le overhead d’une Fagan Inspection complète vaut-il la peine ?

Pour les modules où un défaut a des conséquences graves : logique de distributed consensus, security boundaries, resource lifecycles et state machines. Pour les changements de routine, des adaptations lightweight sont généralement suffisantes. Adaptez le rigor de la relecture au risque réel, pas le même processus à chaque diff.