“`html
System Design
— erros que custam caro
Erros comuns em System Design que você deve evitar
Se você já teve arquitetura “bonita” que falhou em produção, provavelmente não foi falta de tecnologia:
foi falta de decisões explícitas sobre confiabilidade, consistência,
capacidade e observabilidade.
1) Definir requisitos de forma vaga (ou só funcional)
Um dos maiores desperdícios em system design é começar a desenhar componentes antes de transformar
“precisa funcionar” em métricas testáveis.
-
Tempo de resposta sem SLA/SLO (ex.: “rápido”) — em produção isso vira
discussão interminável e nenhuma ação concreta. -
Capacidade sem números (ex.: picos, sazonalidade, tamanho médio e p95) —
você só percebe quando a fila cresce e o custo explode. -
Disponibilidade sem entender impacto (ex.: “99,9% é ok”) —
precisa saber o que quebra, o que pode atrasar e o que não pode falhar.
Regra prática
Antes de escolher banco, fila ou cache, feche: tráfego, latência alvo,
taxa de erro tolerável, consistência necessária e
comportamento em falha.
2) Tratar consistência e concorrência como detalhe
Em sistemas distribuídos, consistência é uma decisão de produto e engenharia — não um “depois a gente ajusta”.
O erro comum é assumir que “o banco resolve”, ignorando concorrência, reprocessamento e bordas de integridade.
-
Não definir idempotência em fluxos com retries — mensagens ou requisições reprocessadas
podem gerar cobranças duplicadas, updates duplicados ou inventário inconsistente. - Escolher o modelo de consistência tarde — e quando percebe, já espalhou suposições por serviços.
-
Atualizações concorrentes sem controle (ex.: sobrescrita “por último que chega”)
— sem versão, sem locks lógicos ou sem invariantes, você cria bugs difíceis de reproduzir. -
Usar transações locais como “garantia global” — transação em um banco não protege
consistência em múltiplos recursos/serviços.
O que eu busco no desenho
Uma estratégia explícita para: deduplicação, ordem (quando importa),
reprocessamento, garantia de integridade e como lidar com
parcialidade.
3) Escalar sem um plano: “vamos adicionar instâncias”
Escalabilidade não é um botão. É um conjunto de escolhas sobre gargalos: CPU, memória, rede,
armazenamento, concorrência e coordenação.
-
Ignorar hot partitions e sharding — o sistema parece escalar até que um conjunto de chaves
concentra a maior parte do tráfego. -
Subestimar o custo de sincronização — operações que exigem coordenação (ou locks distribuídos)
podem destruir throughput. -
Usar filas sem pensar em backlog — se a produção cresce mais rápido que o consumo,
você transforma latência em um problema estrutural. - Não medir p95/p99 — média esconde caudas; caudas ditam a experiência do usuário.
- Cache sem estratégia — cache “por padrão” vira inconsistência e invalidação mal resolvida.
Como evitar
Identifique primeiro o gargalo provável, depois defina mecanismos: backpressure,
rate limiting, particionamento, capacidade de consumo e
tratamento de cauda.
4) Esquecer operação: observabilidade e recuperação
Um design que não foi pensado para operar falha no dia em que algo inesperado acontece.
E, quase sempre, “algo inesperado” vira “silêncio” (erros sem rastreio) ou “efeito cascata”.
-
Falta de logs estruturados e correlação (request-id / trace-id) —
você não encontra a causa raiz. - Alertas sem critério — notificação demais vira ruído; notificação de menos vira incêndio tardio.
- Sem plano de falha — o sistema deve saber quando degradar, pausar, atrasar ou recusar.
- Reprocessamento perigoso — reter mensagens e reprocessar sem idempotência amplifica o problema.
- Backups/restore sem testes — “tem backup” não é um plano; o plano é “restaurar e validar em X minutos”.
Anti-padrão
Não espere o primeiro incidente para descobrir métricas faltantes. O design precisa nascer com
telemetria e mecanismos de recuperação.
Exemplo prático: idempotência para evitar efeitos duplicados
Quando você tem retries (HTTP, filas, eventos), a forma mais comum de “quebrar” é processar a mesma ação duas vezes.
Uma abordagem simples é usar uma chave de idempotência registrada antes de aplicar efeitos.
-- Tabela (exemplo conceitual)
-- idempotency_keys: (idempotency_key, processed_at, result_hash, status)
--
-- Fluxo:
-- 1) Recebe idempotency_key no request
-- 2) Tenta "reservar" a chave com INSERT que falha se existir
-- 3) Se já existe, retorna o resultado anterior (ou status)
--
-- Em SQL (pseudo):
BEGIN;
-- tenta registrar a chave
INSERT INTO idempotency_keys (idempotency_key, processed_at, status)
VALUES (:key, NOW(), 'PROCESSING');
-- se falhar por duplicidade:
-- SELECT status, result_hash FROM idempotency_keys WHERE idempotency_key = :key;
COMMIT;
-- aplica o efeito real...
-- UPDATE idempotency_keys SET status='DONE', result_hash=:hash WHERE idempotency_key=:key;
O ponto não é “qual banco” e sim o contrato: repetição não deve mudar o resultado.
Isso reduz cascata de bugs quando a malha de mensagens ou o cliente reenvia por engano.
Quer elevar seu nível em arquitetura?
Eu recomendo continuar com os próximos conteúdos do yurideveloper.com para você construir um repertório
consistente: desde decisões de modelagem até trade-offs de escalabilidade e operação.
“`
Sou Apaixonado pela programação e estou trilhando o caminho de ter cada diz mais conhecimento e trazer toda minha experiência vinda do Design para a programação resultando em layouts incríveis e idéias inovadoras! Conecte-se Comigo!