2

Rodei gh + jq nos PRs do repositório: a mediana de espera por um humano foi 19,4h

Passei tempo demais discutindo ritmo de time por impressão. "Essa sprint rendeu", "a IA acelerou bastante", "o pessoal está entregando". Nenhuma dessas frases sobrevive a um jq. Então parei de opinar e tirei três números do próprio repositório, sem ferramenta paga, sem instalar agente no pipeline e sem pedir nada para ninguém.

O pano de fundo é o texto da LeadDev que circulou esses dias, "AI-powered teams ship more code but deliver less". A tese é simples de verificar: escrever código ficou barato, revisar e sustentar não. Se isso for verdade no seu repositório, o sintoma aparece na fila de review e na qualidade da suíte, não no gráfico de commits.

Medição 1: quanto tempo um PR espera pelo primeiro humano

A parte chata é separar bot de gente. Linter, dependabot e revisor automático comentam em minutos e derrubam qualquer média para baixo. Filtrei tudo que termina em [bot]:

gh pr list --repo org/repo --state merged --limit 200 \
  --json number,createdAt,comments,reviews > prs.json

jq -r '.[]
  | . as $pr
  | (($pr.comments + $pr.reviews)
      | map(select(.author.login | endswith("[bot]") | not))
      | map(.createdAt) | sort | first) as $h
  | select($h != null)
  | [$pr.number, ((($h | fromdate) - ($pr.createdAt | fromdate)) / 3600)]
  | @tsv' prs.json > espera.tsv

sort -k2 -n espera.tsv | awk '{v[NR]=$2; s+=$2}
  END {printf "n=%d  mediana=%.1fh  media=%.1fh  p90=%.1fh\n",
              NR, v[int((NR+1)/2)], s/NR, v[int(NR*0.9)]}'

Saída:

n=137  mediana=19.4h  media=31.8h  p90=74.6h

Três coisas saltam daí. A mediana passa de um dia útil, então o PR nasce e dorme. A média está 60% acima da mediana, o que quer dizer que existe uma cauda de PRs esquecidos distorcendo qualquer relatório que use média. E o p90 mostra que um em cada dez PRs espera três dias por uma frase humana.

Esse número é a conta que ninguém faz quando decide gerar mais código. Se a produção de diff dobra e a capacidade de revisão continua igual, o excedente não vira entrega, vira fila. Trabalho já feito que envelhece: mais conflito com quem mexeu no mesmo arquivo, mais contexto perdido na cabeça de quem escreveu, mais caro o retorno do revisor.

Se você usa GitLab, o equivalente é glab mr list --json com o mesmo filtro de autor. Se usa nenhum dos dois, dá para tirar do git log com o timestamp do merge commit, com menos precisão.

Medição 2: 92% de cobertura e 41% de mutation score

Peguei um projeto com 92% de cobertura no relatório. Número que faz qualquer comitê relaxar. Rodei mutation testing só no módulo que mexe com faturamento:

Ran 261 mutants in 4m 12s
Killed:      108
Survived:    127
No coverage:  26
Mutation score: 41.37%

Perto de 41% dos mutantes morreram. Traduzindo: dava para alterar mais da metade do comportamento daquele módulo e a suíte continuava verde, e o deploy passava.

A causa estava espalhada em dezenas de testes com esta cara:

test('cria pedido com cupom de desconto', async () => {
  const pedido = await criarPedido({
    itens: [{ sku: 'A1', preco: 100 }],
    cupom: 'BLACK10',
  })

  console.log(pedido.total)
})

O teste chama a função, percorre a linha, sobe a cobertura e não afirma nada. Troque o 0.10 por 0.90 na regra do cupom e ele passa igual. Cobertura mede linha visitada. Comportamento garantido é outra medição, e quase ninguém roda.

O que a geração assistida fez aqui foi barateamento. Produzir 300 casos custa dois minutos, e boa parte nasce sem asserção que importe. A cobertura sobe, a sensação de segurança sobe junto, e o número de incidentes que chega ao cliente fica no mesmo lugar. Se você for rodar uma vez só, rode no módulo que mexe com dinheiro, e compare o score com a cobertura da mesma pasta.

Medição 3: o que voltou em 30 dias

A terceira é a mais grosseira e a mais barata:

git log --since="30 days ago" --no-merges --pretty=%s \
  | grep -Eic '^(revert|hotfix|fix\(urgent\))'

git log --since="30 days ago" --merges --oneline | wc -l

Deu 11 contra 84 no meu recorte, algo perto de 13%. O número absoluto importa menos que a tendência: se ele cresce no mesmo mês em que o volume de PR cresceu, a velocidade extra foi antecipação de trabalho para o mês seguinte. Vale ajustar o grep para a convenção do seu time, porque commit que começa com "ajuste" ou "correção rápida" escapa do filtro.

Onde eu não levaria isso a sério

Se o time tem três pessoas, nenhum legado e está atrás de tração, rodar mutation testing toda semana vai custar mais do que proteger. A fila de review também mede pouco quando duas pessoas trabalham lado a lado no mesmo arquivo. Esse cuidado todo é para quem já tem cliente pagando e sistema que não pode cair na quinta-feira de fechamento.

Também não sei dizer qual mediana de espera é "boa". 19,4h me pareceu ruim para o tamanho do time, mas não tenho base pública decente para comparar, e desconfio de qualquer benchmark de produtividade vendido junto com uma ferramenta.

Duas perguntas honestas para quem já fez isso: como vocês filtram bot na conta do tempo de review, já que hoje metade dos comentários é automática? E quem já rodou mutation testing em módulo crítico viu score bater menos da metade da cobertura, ou eu peguei um caso especialmente feio?


Publicado originalmente no blog da Revin: https://revin.com.br/pt/blog/mais-codigo-menos-produto-ia-o-que-medir

Carregando publicação patrocinada...