O Número que Ninguém Quer Discutir

A revisão informal de código captura entre 15 e 30 por cento dos defeitos presentes no código sendo revisado. Isso não é uma opinião. É uma constatação que foi replicada ao longo de quatro décadas, múltiplas empresas e dezenas de estudos.

Michael Fagan documentou isso na IBM em 1976. Um estudo de 1987 na AT&T Bell Labs encontrou 20 por cento. Um estudo da HP de 1996 encontrou 25 por cento. Um artigo do Microsoft Research de 2013 sobre code review moderno encontrou aproximadamente a mesma faixa. As ferramentas mudaram de cartões perfurados para GitHub, mas a curva de desempenho humana não se moveu.

Se o seu time acha que o pull request review é sua salvaguarda de qualidade, os dados dizem que você está capturando aproximadamente um bug a cada quatro. Os outros três vão para produção.

De Onde Vêm os Números

A metodologia original de Fagan era simples e brutal. Ele injetava defeitos conhecidos no código, executava o processo de revisão e contava quantos os revisores encontravam. Então comparava isso com o total de defeitos que o time eventualmente encontrava através de testes, incidents em produção e relatórios de clientes. A proporção de encontrado-na-revisão em relação a defeitos-totais tornou-se a removal rate.

A ideia central é que o denominador importa. Uma revisão que encontra dez defeitos parece boa até você saber que havia cinquenta no arquivo. Fagan media o denominador completo. A maioria dos times hoje não faz isso.

Estudos subsequentes usaram designs similares. Pesquisadores semeavam defeitos, comparavam tipos de revisão, ou rastreavam defeitos retroativamente da produção para ver onde eles poderiam ter sido capturados. Os resultados se agrupam estreitamente:

Tipo de revisãoDefect removal rateEstudos-chave
Sem revisão0%Baseline
Informal / PR review15-30%Fagan 1976, Porter 1995, Microsoft 2013
Walkthrough estruturado30-50%Yourdon 1979, Weller 1993
Fagan inspection60-90%Fagan 1976, Russell 1991, NASA 2002

A lacuna entre a revisão informal e a estruturada não é pequena. É uma diferença de 3x na defect escape rate.

Por que o PR Review Performa Tão Mal

O problema não é que os revisores sejam ruins no trabalho deles. O problema é que o pull request review não foi projetado para encontrar defeitos. Ele foi projetado para que duas pessoas concordem que o código pode ser mergeado.

Aqui está o que realmente acontece em um PR review típico. O revisor abre o diff. Ele lê o resumo, escaneia as adições, verifica se os testes passam e procura por algo obviamente errado. Isso leva de cinco a quinze minutos. Então ele aprova.

O processo é otimizado para velocidade, não para minúcia. Não há tempo de preparação. O revisor não leu o código ao redor, não rastreou o fluxo de dados nem construiu um modelo mental da mudança. Ele está reagindo a um diff em uma tela, e cérebros humanos são terríveis em encontrar bugs nesse formato.

Um estudo de 2015 de Bacchelli e Bird na Microsoft encontrou que as categorias de comentários de revisão mais comuns não estavam relacionadas a defeitos de forma alguma. As principais categorias eram perguntas sobre intenção, pedidos de esclarecimento e sugestões de melhoria. Achados reais de defeitos eram uma minoria dos comentários. A ferramenta estava funcionando como um canal de comunicação, não como uma quality gate.

Isso está bem se você sabe o que a ferramenta faz. É perigoso se você acha que ela faz outra coisa.

O que a Revisão Estruturada Faz de Diferente

As Fagan inspections e outros métodos de revisão estruturada alcançam removal rates mais altos mudando o design do processo, não as pessoas.

A maior alavanca é a preparação individual. Em uma Fagan inspection, cada revisor passa tempo focado com o material antes de qualquer discussão em grupo. Fagan descobriu que inspectores preparados encontravam aproximadamente o dobro de defeitos do que aqueles que entravam a frio. O modelo de PR é o modelo de entrada a frio por padrão.

A segunda alavanca é o ritmo. Fagan recomendou 100 a 125 linhas de código por hora de revisão. A maioria dos revisores de PR processa dez vezes essa taxa. Velocidade mata detecção. Seu cérebro preenche padrões esperados em vez de ler o que está realmente lá.

A terceira alavanca é o foco. Reuniões de Fagan têm um único propósito: registrar defeitos. Sem debates de design. Sem propostas de solução. Sem discussões de estilo. Threads de PR rotineiramente derivam para opiniões de arquitetura, o que consome o mesmo orçamento cognitivo que poderia ter encontrado um null dereference.

A quarta alavanca é o papel do leitor. Ter alguém que não escreveu o código parafraseá-lo em voz alta força o grupo a processar na velocidade de compreensão em vez da velocidade de varredura. Um diff em uma tela deixa seus olhos pular as partes chatas. Uma pessoa falando não pula.

O Argumento de Custo Está Invertido

A objeção usual à revisão estruturada é o custo. Uma Fagan inspection consome quatro a seis horas-pessoa para algumas centenas de linhas de código. Um PR review consome quinze minutos do tempo de uma pessoa. A conta parece óbvia.

Ela é óbvia, e está errada.

Fagan também mediu o custo de encontrar defeitos em diferentes estágios. Um defeito encontrado durante a inspection custava cerca de um décimo do que custava encontrá-lo durante os testes. Quando escapava para produção, a proporção crescia para vinte ou trinta para um. O estudo da NASA de 2002 encontrou que cada hora gasta em inspection prevenia uma média de 33 horas de trabalho de manutenção depois.

As economias são invisíveis. Você não pode medir o bug que preveniu. O custo da reunião é imediato e óbvio. É por isso que as organizações otimizam a velocidade visível em vez da qualidade invisível, mesmo quando os dados dizem que isso acaba custando mais no final.

Um Meio-termo Orientado por Dados

Você não precisa da cultura de reuniões da IBM para obter a maior parte do benefício. Você precisa emprestar as características do processo que realmente movem o número, e descartar as que não movem.

Aqui está o que os dados dizem que importa:

  1. Tempo de preparação. Exija que os revisores passem tempo com o código antes de comentar. Até dez minutos de leitura focada superam uma passada rápida.

  2. Limites de ritmo. Para arquivos críticos, imponha uma velocidade máxima de revisão. Se um revisor aprova uma mudança de 500 linhas em cinco minutos, isso são dados, não diligência.

  3. Foco apenas em defeitos. Separe o feedback de estilo e arquitetura da caça a defeitos. Use formatadores automáticos para o primeiro. Reserve a atenção humana para o segundo.

  4. Checklists. Fagan descobriu que revisores guiados por checklist encontravam defeitos que revisores guiados por intuição deixavam passar. A checklist existe porque a expertise cria pontos cegos.

Aqui está um script leve que mede a profundidade de revisão do histórico do Git. Ele estima se uma revisão teve tempo suficiente para ser minuciosa:

#!/usr/bin/env python3
"""Estimate review depth from git history."""

import subprocess
import sys
from datetime import datetime, timezone


def get_commit_info(commit_hash: str) -> dict:
    """Return author, committer, and timestamps for a commit."""
    fmt = "%H|%an|%cn|%ad|%cd"
    result = subprocess.run(
        ["git", "log", "-1", f"--format={fmt}", commit_hash],
        capture_output=True,
        text=True,
        check=True,
    )
    parts = result.stdout.strip().split("|")
    return {
        "hash": parts[0],
        "author": parts[1],
        "committer": parts[2],
        "author_date": datetime.strptime(parts[3], "%a %b %d %H:%M:%S %Y %z"),
        "commit_date": datetime.strptime(parts[4], "%a %b %d %H:%M:%S %Y %z"),
    }


def get_lines_changed(commit_hash: str) -> int:
    """Count total lines added + deleted in a commit."""
    result = subprocess.run(
        ["git", "diff", f"{commit_hash}^", commit_hash, "--stat"],
        capture_output=True,
        text=True,
        check=True,
    )
    # Last line of --stat contains totals like "3 files changed, 42 insertions(+), 7 deletions(-)"
    for line in reversed(result.stdout.strip().splitlines()):
        line = line.strip()
        if "insertions" in line or "deletions" in line:
            # Extract numbers roughly
            parts = line.split(",")
            total = 0
            for part in parts:
                digits = "".join(ch for ch in part if ch.isdigit())
                if digits:
                    total += int(digits)
            return total
    return 0


def estimate_review_depth(commit_hash: str) -> dict:
    """Estimate whether a commit had time for thorough review.

    Returns lines changed, time between author and commit dates
    (a rough proxy for review duration), and a verdict.
    """
    info = get_commit_info(commit_hash)
    lines = get_lines_changed(commit_hash)

    # Time between author date and commit date is a proxy for review time
    # In many workflows, commit date reflects when the merge happened
    review_seconds = (info["commit_date"] - info["author_date"]).total_seconds()
    review_hours = review_seconds / 3600

    # Fagan recommended 100-125 lines/hour for thorough review
    fagan_rate = 125
    needed_hours = lines / fagan_rate if lines else 0

    verdict = "insufficient"
    if review_hours >= needed_hours:
        verdict = "adequate"
    if review_hours >= needed_hours * 2:
        verdict = "thorough"

    return {
        "hash": commit_hash[:8],
        "lines": lines,
        "review_hours": round(review_hours, 2),
        "needed_hours": round(needed_hours, 2),
        "verdict": verdict,
    }


if __name__ == "__main__":
    commit = sys.argv[1] if len(sys.argv) > 1 else "HEAD"
    result = estimate_review_depth(commit)
    print(f"Commit:       {result['hash']}")
    print(f"Lines:        {result['lines']}")
    print(f"Review time:  {result['review_hours']} hours")
    print(f"Fagan time:   {result['needed_hours']} hours")
    print(f"Verdict:      {result['verdict']}")

Salve como review_depth.py e execute:

python review_depth.py abc1234

A saída dirá se um commit teve tempo de revisão suficiente para ser minucioso pelo padrão de Fagan. A maioria dos commits dirá insufficient. Esse é o ponto. Os dados têm nos dito isso por décadas, e continuamos construindo pipelines mais rápidos em vez de melhores.

O que Isso Significa para o Seu Time

O pull request review não é inútil. Ele construi contexto compartilhado, espalha conhecimento e captura erros óbvios. Mas os dados são claros sobre o que ele não faz. Ele não captura a maioria dos defeitos.

Se sua estratégia de qualidade depende do PR review como filtro principal, você está filtrando com uma peneira. A removal rate de 15-30% não é uma falha dos seus revisores. É uma propriedade do processo.

Os times que superam esse número não contratam pessoas mais inteligentes. Eles mudam o processo. Eles adicionam tempo de preparação, impõem limites de ritmo, separam a caça a defeitos da discussão de design, e usam checklists para direcionar a atenção para onde a intuição erra.

Você não precisa de uma Fagan inspection completa para cada diff. Você precisa saber o que seu processo atual realmente alcança, e parar de fingir que alcança mais.

FAQ

O que os dados dizem sobre a efetividade do pull request review?

Múltiplos estudos na IBM, AT&T, HP e Microsoft encontram consistentemente que a revisão informal de código captura 15-30% dos defeitos presentes no código. Essa faixa permaneceu estável desde os anos 1970 até a pesquisa moderna sobre workflows baseados em GitHub.

Por que os pull request reviews capturam tão poucos defeitos?

O PR review é otimizado para velocidade e aprovação de merge, não para detecção sistemática de defeitos. Os revisores tipicamente gastam 5-15 minutos por revisão, não têm tempo de preparação, processam o código a 10x a taxa que a pesquisa recomenda, e o formato incentiva a leitura rápida em vez da análise profunda.

Quanto melhores são as revisões estruturadas como as Fagan inspections?

As Fagan inspections relatam consistentemente defect removal rates de 60-90%, aproximadamente 3-4x melhores que a revisão informal. A diferença vem da preparação individual, limites de ritmo impostos, separação de papéis, foco guiado por checklist, e reuniões que registram defeitos em vez de debater soluções.

Qual é a maneira mais barata de melhorar a efetividade do PR review?

Exija preparação individual antes de comentar, use checklists adaptadas aos tipos de defeitos comuns do seu time, separe feedback de estilo da caça a defeitos, e limite a velocidade de revisão para arquivos críticos. Mesmo pequenas mudanças na preparação e no foco podem mover a agulha significativamente sem adicionar overhead de reuniões.

Como eu meço a defect removal rate real do meu time?

Acompanhe os defeitos encontrados na revisão versus os defeitos encontrados posteriormente em testes ou produção. A proporção de capturado-cedo em relação a total-encontrado é sua removal rate. A maioria dos times não acompanha isso, e é por isso que superestimam a efetividade da revisão. Comece a registrar onde cada defeito foi encontrado, depois calcule a proporção mensalmente.