Metodologia9 min

Anti-patterns de Performance: erros que você deve evitar

Conheça os erros mais comuns que destroem performance e como evitá-los antes que causem problemas.

Alguns padrões de desenvolvimento parecem inofensivos ou até boas ideias, mas devastam performance quando o sistema escala. Esses são os anti-patterns — práticas que funcionam no desenvolvimento mas falham em produção.

Este artigo apresenta os anti-patterns mais comuns e como evitá-los.

O código que funciona no laptop do desenvolvedor não necessariamente funciona com 10.000 usuários simultâneos.

Anti-patterns de Código

1. N+1 Queries

O problema:

// Busca 100 pedidos, depois 100 queries para clientes
const orders = await Order.findAll();
for (const order of orders) {
    order.customer = await Customer.findById(order.customerId);
}
// 101 queries ao banco

A solução:

// Uma query com JOIN
const orders = await Order.findAll({
    include: [Customer]
});
// 1 query ao banco

2. Serialização em Loop

O problema:

const results = [];
for (const item of items) {
    results.push(JSON.stringify(item)); // Serializa um por um
}

A solução:

const results = JSON.stringify(items); // Serializa tudo de uma vez

3. Concatenação de Strings em Loop

O problema:

String result = "";
for (String s : strings) {
    result += s; // Cria nova string a cada iteração
}

A solução:

StringBuilder sb = new StringBuilder();
for (String s : strings) {
    sb.append(s);
}
String result = sb.toString();

4. Chamadas Síncronas Desnecessárias

O problema:

const user = await getUser(id);
const orders = await getOrders(id);
const recommendations = await getRecommendations(id);
// 3 chamadas sequenciais = soma das latências

A solução:

const [user, orders, recommendations] = await Promise.all([
    getUser(id),
    getOrders(id),
    getRecommendations(id)
]);
// 3 chamadas paralelas = máximo das latências

5. Regex Mal Construída

O problema:

// Regex com backtracking exponencial
const regex = /^(a+)+$/;
regex.test("aaaaaaaaaaaaaaaaaaaaaaaaaaaaab"); // Trava!

A solução:

// Regex sem backtracking problemático
const regex = /^a+$/;

Anti-patterns de Arquitetura

6. Banco de Dados como Fila

O problema:

-- Polling constante
SELECT * FROM jobs WHERE status = 'pending' LIMIT 1;
UPDATE jobs SET status = 'processing' WHERE id = ?;

Por que é ruim:

  • Polling constante consome recursos
  • Contenção em atualizações
  • Não escala

A solução: Use uma fila de verdade: RabbitMQ, SQS, Kafka.

7. Cache sem Limite

O problema:

const cache = new Map();
function get(key) {
    if (!cache.has(key)) {
        cache.set(key, fetchFromDB(key));
    }
    return cache.get(key);
}
// Cache cresce infinitamente

A solução:

// Use LRU cache com limite
const cache = new LRUCache({ max: 1000 });

8. Log Síncrono em Path Crítico

O problema:

async function handleRequest(req) {
    await logger.log('Request received'); // Espera I/O
    const result = process(req);
    await logger.log('Request processed'); // Espera I/O novamente
    return result;
}

A solução:

async function handleRequest(req) {
    logger.log('Request received'); // Assíncrono, fire-and-forget
    const result = process(req);
    logger.log('Request processed');
    return result;
}

9. Transações Longas

O problema:

await db.beginTransaction();
const user = await db.getUser(id);
await externalAPI.validate(user); // Chamada externa DENTRO da transação
await db.updateUser(user);
await db.commit();
// Transação segura lock por tempo da chamada externa

A solução:

const user = await db.getUser(id);
await externalAPI.validate(user); // FORA da transação

await db.beginTransaction();
await db.updateUser(user);
await db.commit();

10. Retry sem Backoff

O problema:

while (!success) {
    success = await tryOperation();
    // Retry imediato em loop tight
}

A solução:

let delay = 100;
while (!success && attempts < maxAttempts) {
    success = await tryOperation();
    if (!success) {
        await sleep(delay);
        delay *= 2; // Exponential backoff
    }
}

Anti-patterns de Infraestrutura

11. Configurações Default em Produção

O problema:

# Connection pool default: 10 conexões
# Timeout default: 30 segundos
# Buffer default: 8KB

Por que é ruim: Defaults são para desenvolvimento, não produção.

A solução: Tune cada configuração para seu workload:

pool_size: 50
timeout: 5s
buffer: 64KB

12. Logs em DEBUG em Produção

O problema:

DEBUG: Entering function processOrder
DEBUG: Parameter validation passed
DEBUG: Calling database
DEBUG: Query took 5ms
DEBUG: Processing result...
// Milhões de linhas por hora

A solução:

# Produção: ERROR e WARNING apenas
log_level: WARN

13. Health Check que Faz Trabalho Real

O problema:

app.get('/health', async (req, res) => {
    const dbCheck = await db.query('SELECT 1');
    const cacheCheck = await cache.ping();
    const apiCheck = await externalAPI.status();
    res.json({ status: 'healthy' });
});
// Health check consome recursos e pode falhar por causa de dependências

A solução:

// Liveness: apenas verifica se app está rodando
app.get('/health/live', (req, res) => res.json({ status: 'ok' }));

// Readiness: verifica dependências (menos frequente)
app.get('/health/ready', async (req, res) => {
    // Checks mais leves e com timeout curto
});

Anti-patterns de Teste

14. Testar com Dados Irreais

O problema:

// Teste com 10 registros
// Produção tem 10 milhões

A solução: Teste com volume similar à produção ou projeções realistas.

15. Ignorar Warm-up

O problema:

Teste de 5 minutos:
- 2 min warm-up (ignorado)
- 3 min steady state
= Dados insuficientes e distorcidos

A solução: Exclua warm-up das métricas e tenha steady state longo o suficiente.

16. Medir Apenas Média

O problema:

Latência média: 50ms ✓
Latência p99: 5000ms ✗ (escondida pela média)

A solução: Sempre meça percentis: p50, p90, p95, p99.

Como Evitar Anti-patterns

1. Code Review focado em performance

Checklist:

  • Tem loops com I/O dentro?
  • Queries podem ser batched?
  • Operações podem ser paralelas?
  • Cache tem limite?
  • Logs são apropriados para produção?

2. Testes de carga regulares

Encontre problemas antes que usuários encontrem.

3. Profiling em produção

Use APM para identificar hotspots reais, não supostos.

4. Cultura de performance

Performance não é tarefa de um time. É responsabilidade de todos.

Conclusão

Anti-patterns são armadilhas esperando para serem ativadas quando seu sistema escala. A maioria:

  • Funciona bem em desenvolvimento
  • Falha espetacularmente em produção
  • É difícil de identificar sem testes adequados

Para evitá-los:

  1. Conheça os anti-patterns comuns
  2. Revise código com olhar de performance
  3. Teste com carga realista
  4. Monitore comportamento em produção

O melhor momento para evitar um anti-pattern é antes de escrevê-lo. O segundo melhor é agora.

anti-patternsboas práticaserrosotimização
Compartilhar:
Read in English

Quer entender os limites da sua plataforma?

Entre em contato para uma avaliação de performance.

Fale Conosco