SkillEngenhariaRevisão

Reviewing Performance

Identifica problemas de performance introduzidos pelo PR: complexidade, queries ineficientes e gargalos.

Ações
PerfilDev
ProfundidadeAlta
Idiomaen-US
Objetivo

Em uma frase.

Identificar regressões de performance introduzidas pelo PR — cobrindo complexidade algorítmica, queries ineficientes, alocações desnecessárias de memória, operações bloqueantes em contextos assíncronos e gargalos em caminhos críticos de execução.

Aplicação

Quando
faz sentido.

Usar
  • Como etapa de revisão de performance de qualquer PR que toque lógica de processamento de dados, acesso a banco, chamadas de rede, loops sobre coleções ou caminhos críticos do sistema.
  • Quando o PR é executado em contexto de alta carga ou frequência (endpoint de alta utilização, worker, job batch).
  • Quando o PR altera código que já demonstrou problemas de performance anteriormente.
Não usar
  • Para micro-otimizações sem impacto mensurável — o foco é em regressões reais.
  • Para revisão de lógica ou segurança — use as skills correspondentes.
  • Antes de executar understanding-pr-scope — é necessário identificar hot paths antes de revisar performance.
Prompt

Instruções
para a IA.

Passo 1 — Identificar hot paths no diff

Antes de analisar qualquer linha, classificar cada mudança por relevância de performance:

**Hot path (alta prioridade de revisão):**

- Código chamado em cada request HTTP ou mensagem processada. - Loops sobre coleções cujo tamanho cresce com dados do usuário ou volume de sistema. - Código executado em jobs batch ou workers de processamento contínuo. - Código de renderização ou serialização de dados chamado com alta frequência.

**Cold path (menor prioridade):** - Código de inicialização executado uma vez. - Handlers de erro raramente acionados. - Código administrativo de baixa frequência.

Focar a análise dos passos seguintes nos hot paths identificados.

Passo 2 — Verificar complexidade algorítmica

Para cada loop ou estrutura de iteração em hot paths:

- Qual é a complexidade de tempo: O(1), O(n), O(n²), O(n log n)?

- O tamanho de `n` é controlado ou pode crescer indefinidamente com dados de produção? - Há loops aninhados onde o produto dos tamanhos pode ser explosivo? - Operações de busca dentro de loops usam estruturas de dados adequadas (Set/Map para O(1) vs. Array para O(n))?

Sinalizar qualquer mudança que piore a complexidade assintótica de um algoritmo em hot paths.

Passo 3 — Verificar acesso ao banco de dados

Para cada interação com banco de dados no diff:

**Problema N+1:**

- Há uma query executada dentro de um loop? - A query é chamada uma vez para obter uma lista e depois N vezes para buscar dados relacionados de cada item? - O ORM está carregando relacionamentos de forma lazy quando eager loading seria necessário?

**Queries sem índice:** - A query filtra ou ordena por colunas que provavelmente não têm índice (novas colunas, colunas raramente usadas)? - Há uso de `LIKE '%termo%'` que impede uso de índice B-tree? - Há queries que fazem full table scan em tabelas de grande volume?

**Volume de dados:** - Queries sem `LIMIT` em tabelas que podem ter volume ilimitado? - SELECT * retornando colunas desnecessárias (especialmente blobs ou campos grandes)?

Passo 4 — Verificar alocações de memória desnecessárias

Para operações que criam novos objetos ou coleções em hot paths:

- Há criação de objetos intermediários descartados imediatamente dentro de loops?

- Arrays ou strings sendo construídos por concatenação em vez de usando builders eficientes? - Cópias desnecessárias de grandes coleções quando operação in-place seria possível? - Buffers sendo alocados com tamanho fixo grande quando tamanho variável seria mais eficiente? - Closures capturando referências a objetos grandes desnecessariamente?

Passo 5 — Verificar operações bloqueantes em contextos assíncronos

Para código que roda em event loop, worker threads ou contextos concorrentes:

- Há chamadas síncronas de I/O (leitura de arquivo, chamada de rede, query de DB) em contexto que deveria ser assíncrono?

- Há operações CPU-intensivas longas sem yield ao event loop? - Promises sendo criadas e descartadas sem tratamento (fire-and-forget sem controle de erro)? - Await em loop sequencial onde `Promise.all` permitiria execução paralela? - Timeouts ou retries sem limite de tentativas que podem causar acúmulo de operações?

Passo 6 — Verificar ausência de cache onde necessário

Quando o código executa operações caras e repetíveis:

- Resultados de chamadas externas (APIs, DB) são cacheados quando o dado raramente muda?

- Computações idempotentes caras são memoizadas quando chamadas repetidamente com os mesmos inputs? - Cache existente está sendo invalidado corretamente após mudanças que tornam dados obsoletos?

---
Casos

Exemplos
de uso.

---

## Exemplo 1 — N+1 query em listagem de pedidos