Dos revisores, un diff, cero superposición

Dos ingenieros senior revisan el mismo pull request. Uno señala un null check faltante. El otro detecta una race condition en el cleanup path. Ninguno encuentra ambos.

Si hubieras asignado solo un revisor, uno de esos bugs habría salido a producción. Esto no es una brecha de habilidades. Es una propiedad predecible de la attention humana, y Michael Fagan la documentó en IBM en 1976.

Fagan estaba midiendo las tasas de detección de defectos en el pipeline de software de IBM. Sus datos mostraron algo incómodo: incluso los inspectores experimentados detectaban solo una fracción del total de defectos que el grupo eventualmente encontraba. El verdadero valor no estaba en la experiencia de ninguna persona individual. Estaba en la combinación estructurada de múltiples perspectivas.

La mayoría de los equipos hoy no estructuran esa combinación. Un ingeniero senior hojea un diff entre reuniones, nota un issue de estilo, aprueba y sigue adelante. El siguiente revisor hace lo mismo. Ambos pasan por alto el error off-by-one que corrompe los datos de producción el martes siguiente.

Fagan llamó a esto el síndrome de revisión no estructurada. El grupo tiene ojos, pero no tiene proceso.

Qué es en realidad una Fagan Inspection

Una Fagan Inspection no es una reunión donde la gente lee código junta y comparte sentimientos. Es un proceso formal con roles definidos, criterios de entrada y output medible. Fagan la diseñó porque las revisiones no estructuradas desperdiciaban tiempo y dejaban pasar defectos aproximadamente al mismo ritmo que no hacer revisión alguna.

La idea central es la separación de roles. Cada uno tiene exactamente un trabajo:

  • El moderator dirige la reunión y hace cumplir las reglas. No inspecciona.
  • El reader parafrasea el código en voz alta. Esto obliga al grupo a confrontar lo que el código realmente hace, no lo que el author pretendía.
  • El tester piensa en execution paths, boundary conditions y coverage gaps.
  • El author responde preguntas pero no defiende el código.

Esta separación previene el failure mode más común de la revisión grupal: el author convenciendo a todos de que sus preocupaciones no son válidas.

Cuando el author también es quien explica, suaviza la ambigüedad. “Oh, esa variable siempre es establecida por el caller.” El grupo asiente. Nadie verifica. El rol de reader existe para romper este hábito. Si el reader no puede parafrasear una función en una oración, la función no está lista para salir.

Por qué las checklists vencen a la intuición

Fagan también introdujo inspection checklists. No son estándares de código genéricos copiados de una guía de estilo. Están adaptadas al tipo específico de artefacto que se está revisando.

Una checklist para una state machine pregunta: ¿manejaste cada transición? Una checklist para un resource allocator pregunta: ¿cada allocation está emparejada con una deallocation en cada path?

La checklist existe porque la attention humana es irregular. Un experto que ha escrito diez mil queries de base de datos saltará mentalmente el bloque BEGIN TRANSACTION. Su cerebro lo autocompleta como correcto. Fagan descubrió que los inspectores guiados por checklists encontraban defectos que los revisores guiados por intuición pasaban por alto, no porque los expertos fueran descuidados, sino porque la expertise crea blind spots.

Aquí hay una checklist lightweight para una sola función de 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?",
]

Esto no es burocracia. Es una forcing function para la attention sistemática.

Fagan dividió las inspecciones en cuatro fases, y la reunión es la más corta

Una Fagan Inspection real tiene cuatro fases, y la reunión en sí es la más corta.

Preparation. Cada inspector revisa el material solo, con la checklist, antes de que el grupo se reúna. Fagan descubrió que los inspectores preparados encontraban aproximadamente el doble de defectos que aquellos que llegaban en frío. La reunión existe solo para combinar hallazgos, no para generarlos.

La reunión. El reader recorre el código. El tester hace preguntas de qué pasaría si. El moderator lo mantiene bajo dos horas. El author toma notas. Nadie arregla código durante la reunión. Los defectos se registran y el grupo sigue adelante.

Rework. El author arregla los defectos registrados solo.

Follow-up. El moderator verifica que cada defecto fue atendido. Reworks grandes pueden desencadenar una segunda inspección.

Esta estructura se siente pesada para un pull request moderno. Fagan la diseñó para software de mainframe donde un solo defecto podía costar millones. Los principios aún se adaptan a contextos más pequeños.

Dónde esto se vuelve excesivo

Las Fagan Inspections no son gratis. El tiempo de preparation solo añade una sobrecarga significativa. Para un bugfix de diez líneas, una Fagan Inspection completa es absurda. No necesitas cuatro personas y una checklist para detectar un import faltante.

La curva de retorno no es lineal. Los datos de Fagan sugerían que las inspecciones rendían más para modules complejos y de alto riesgo: state machines, parsers, resource managers, cualquier cosa con non-local state o constraints de ordering sutiles. Para handlers CRUD y tests boilerplate, la revisión informal está bien.

El verdadero error es aplicar la misma estrategia de revisión a cada cambio. Un typo en un mensaje de log no necesita una Fagan Inspection. Un distributed transaction coordinator probablemente sí.

Una versión lightweight que puedes usar hoy

No necesitas la cultura de reuniones de IBM para obtener la mayor parte del beneficio. Aquí hay una adaptación lightweight que funciona para equipos modernos:

  1. Requerir revisión individual antes de la discusión grupal. Cada revisor envía comentarios escritos antes de que alguien hable. Esto evita que la primera opinión fuerte domine.

  2. Rotar el rol de reader. Pide a un revisor que resuma el cambio con sus propias palabras antes de que nadie lo critique. Si no puede, el cambio es demasiado grande o poco claro.

  3. Construir una checklist del equipo. Empieza con las siete preguntas de arriba. Agrega items específicos del dominio. Revísala trimestralmente.

  4. Separar author y defender. El author responde preguntas factuales. No argumenta que el código está bien. Si un revisor está confundido, eso es un dato, no un debate.

  5. Registrar defectos, arreglarlos después. No reescribas código durante la revisión. Registra el issue, termina, luego arregla.

Aquí hay un script simple para generar una review checklist para cualquier module de 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}")

Ejecútalo así:

python inspection_checklist.py src/transaction.py

No encontrará tus bugs. Te obliga a mirar en los lugares correctos.

Contratar gente más inteligente no arreglará un problema de proceso

La investigación de Fagan tiene casi cincuenta años, pero el hallazgo no ha cambiado. Los revisores individuales son inconsistentes. Los grupos también son inconsistentes, a menos que los estructures. La varianza entre revisores no es un problema que eliminar. Es un recurso que organizar.

La próxima vez que un revisor encuentre un bug que otro pasó por alto, no preguntes quién es mejor. Pregunta si tu proceso es lo suficientemente estructurado para combinar lo que ambos ven. Fagan ya intentó contratar su salida de esto. No funciona.

FAQ

¿Qué es una Fagan Inspection?

Una Fagan Inspection es un proceso formal y estructurado de code review desarrollado por Michael Fagan en IBM en 1976. Utiliza roles definidos (moderator, reader, tester, author), requisitos de preparation y checklists para maximizar la detección de defectos en artefactos de software.

¿Por qué diferentes revisores encuentran diferentes bugs?

La attention humana es selectiva. Los expertos desarrollan atajos mentales que les permiten leer código rápidamente, pero esos mismos atajos crean blind spots. Diferentes revisores tienen diferentes backgrounds y patrones cognitivos, por lo que sus blind spots no se superponen perfectamente. La investigación de Fagan mostró que el valor de la inspección proviene de combinar múltiples perspectivas incompletas, no de encontrar un revisor perfecto.

¿Se siguen usando las Fagan Inspections hoy?

El proceso formal completo es raro fuera de industrias críticas para la seguridad como aeroespacial y dispositivos médicos. Sin embargo, los principios subyacentes —preparación individual, separación de roles y revisión guiada por checklists— son cada vez más adaptados por equipos de software de alto rendimiento. Las ideas centrales también influyeron en prácticas modernas como walkthroughs estructurados y technical reviews formales.

¿Cuándo vale la pena el overhead de una Fagan Inspection completa?

Para modules donde un defecto tiene consecuencias severas: lógica de distributed consensus, boundaries de seguridad, lifecycles de recursos y state machines. Para cambios rutinarios, las adaptaciones lightweight suelen ser suficientes. Adapta el rigor de la revisión al riesgo real, no el mismo proceso a cada diff.