Pilar Code Quality - Visão geral
Você leu cinco posts sobre métricas individuais. Cada uma cobre uma dimensão. Mas a saúde do código não é uma métrica — é o conjunto. E é olhando o..
Os testes passam. O código compila. O comportamento "errado" nunca acontece, então ninguém abre incident. Mas o bug está latente — esperando o caminho certo de execução para se manifestar. Análise estática profunda encontra ele antes.
Tem código no seu repo que nunca pode ser executado. Você não sabe quais. Linhas escritas, revisadas e mergeadas — mas que jamais entram em qualquer caminho real de execução. Bug Analysis é a categoria de análise estática que descobre isso.
Bug Analysis é análise estática focada em erros lógicos: condições impossíveis, dead code, loops sem condição de parada, exceções engolidas. Encontra bugs antes dos testes rodarem — que é onde detectar erro é mais barato. Não substitui testes; complementa.
if que nunca pode executar — e quantos casos como esse existem no seu repoVocê herdou um sistema. Em algum lugar dele, existe uma função assim:
function processOrder(order) {
const status = order.status.toUpperCase();
if (status === 'PENDING') {
return queue(order);
}
if (status === 'pending') { // ← este bloco nunca executa
return retry(order);
}
return reject(order);
}
O segundo if nunca pode ser verdadeiro. A primeira linha forçou maiúsculas; comparar com lowercase é logicamente impossível. Esse retry(order) nunca foi chamado uma única vez — provavelmente desde o dia que esse código foi escrito.
Quantos casos assim existem no seu repo agora? Sinceramente — você não sabe. Os testes passam. O código compila. O comportamento "errado" nunca acontece, então ninguém abre incident. O bug está latente.
Bug Analysis é a categoria de análise estática que encontra exatamente isso.
Code Smells (do post anterior) são design ruim que aumenta probabilidade de bug.
Bug Analysis encontra bugs lógicos — código que está sintaticamente correto, mas logicamente impossível de fazer o que parece que faz. A diferença:
| Code Smell | Bug Lógico (Bug Analysis) | |
|---|---|---|
| Natureza | Padrão de design ruim | Erro de lógica concreto |
| Comportamento | Funciona, mas é frágil | Não funciona como o autor pensou |
| Detecção | Catálogo de padrões | Análise de fluxo de dados |
| Exemplo | Método com 200 linhas | if cuja condição sempre é falsa |
Os dois são detectados por análise estática. Mas Bug Analysis exige análise de fluxo de dados (data flow analysis) — algoritmos que rastreiam como uma variável é modificada ao longo da execução para inferir valores possíveis em cada ponto.
São três famílias principais de erro lógico.
O exemplo do if que sempre é falso. Variantes incluem:
// Comparação tautológica
if (x > 0 && x < 0) { ... } // sempre falso
// Variável já fixada
const role = 'admin';
if (role === 'user') { ... } // sempre falso
// Tipo incompatível
if (typeof n === 'number' && n.startsWith('A')) { ... }
// método não existe em number
O mecanismo: o analisador rastreia o tipo e o conjunto de valores possíveis de cada variável. Quando a condição exige um valor que não pertence ao conjunto, ela é classificada como sempre falsa (ou sempre verdadeira). O bloco correspondente é dead code.
function findUser(id) {
let user = repository.firstUser();
while (user) { // ← user nunca é reatribuído dentro do loop
if (user.id === id) return user;
}
}
O loop continua enquanto user for verdadeiro (ou existir), mas nada dentro do loop muda user. Se firstUser() retorna alguém que tem id diferente do recebido pela função, esse loop nunca termina. Em produção, isso vira CPU 100% e timeout silencioso.
Bug Analysis detecta isso rastreando se a variável de controle do loop pode efetivamente mudar entre iterações.
try {
const result = riskyOperation();
return process(result);
} catch (e) {
// silently ignored
}
O catch captura a exceção e não faz nada. Não loga, não relança, não retorna fallback explícito. Do ponto de vista da função, parece que tudo deu certo (porque não vazou exceção), mas process(result) nunca foi chamado e quem chama essa função recebe undefined.
Esse padrão é especialmente perigoso porque mascara a causa raiz de problemas em produção. O sistema "funciona" mas com comportamento errado, e o log não tem rastro.
“Detectar erro durante a escrita custa 1×. Detectar em produção custa 100×. Bug Analysis intervém no momento mais barato.
A justificativa econômica do Bug Analysis é o conceito de shift-left quality: detectar erro o mais cedo possível no ciclo de desenvolvimento.
(Os números variam por estudo, mas a ordem de magnitude é consistente desde o trabalho clássico de Boehm.)
Bug Analysis roda no editor (via plugin), no commit (via hook) ou no PR (via CI rápido). Encontra o erro antes do teste ser escrito. O autor corrige imediatamente, com o contexto fresco. Não vira ticket, não vira pull request, não vira retrabalho.
Importante: Bug Analysis e teste automatizado são complementares, não substitutos.
Bug Analysis não sabe se sua função está calculando o desconto certo. Só sabe se a função tem caminhos lógicos impossíveis. Para validar a regra de negócio, você precisa do teste.
Da literatura de qualidade de software vem uma distinção útil:
Um bug lógico pode existir por anos sem virar defeito visível — porque o caminho que o ativaria nunca é executado. Mas a sua existência indica código não-determinístico: você não consegue garantir o que ele faz em todos os cenários.
Sistemas com muitos bugs lógicos detectados estaticamente são instáveis — não porque vão quebrar agora, mas porque ninguém sabe quando vão quebrar.
Bugs lógicos gerados por IA são especialmente perigosos porque passam revisão humana — parecem corretos sintaticamente. Quando o LLM gera uma função, ele otimiza por "código que compila e parece razoável", não por "código com lógica completa". Resultado: condições impossíveis, ramos que nunca executam, exceções engolidas — todos os tipos de bug que análise estática profunda pega entram silenciosamente nos commits gerados por IA.
if no nível 4 nunca executa. Ela adiciona código no caminho morto, pensando que está implementando.no-constant-condition e no-unreachable (JS/TS) — ou a plataforma SQA da Codurance que integra Bug Analysis com as outras quatro métricas da série.Os quatro posts até aqui (Ciclomática, Cognitiva, Smells, Bugs) tratam de problemas localizados — em uma função, em um arquivo. O próximo post fala da métrica que captura um problema sistêmico: Code Duplication. E é o problema mais perigoso porque ele se espalha sem aparecer no radar.
Code Duplication→A Codurance acompanha times de engenharia que querem instrumentar a saúde do código sem virar gestores. Ajudamos Tech Leads e Staff Engineers a integrar Bug Analysis em pre-commit hooks e PR checks, definir thresholds de severidade e estabelecer processos de triagem que evitam que bugs lógicos virem defeitos em produção.
Se você quer aplicar essas práticas no seu time, entre em contato hoje.
Você leu cinco posts sobre métricas individuais. Cada uma cobre uma dimensão. Mas a saúde do código não é uma métrica — é o conjunto. E é olhando o..
Você corrigiu uma cópia da lógica. Existem outras duas que você não sabia que existiam. Os testes da função "oficial" passam. O caminho que o usuário..
"Isso aqui está estranho" não é um comentário de PR review. É uma sensação que precisa de nome próprio. Em 1999, Kent Beck e Martin Fowler nomearam..
Junte-se à nossa newsletter para obter dicas de especialistas e estudos de caso inspiradores
Junte-se à nossa newsletter para obter dicas de especialistas e estudos de caso inspiradores