Publicações | Codurance

Code Smells: armadilhas catalogadas que viram bug e por que Beck e Fowler deram nome a elas

Written by Mauro Ribeiro | 16 mai 2026

"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 dezenas dessas sensações para que o time pare de discutir percepção e comece a apontar problema.

TL;DR

Code Smells não são bugs, não são estilo. São padrões de design ruim que aumentam a probabilidade de bugs futuros e dificultam manutenção. Beck e Fowler nomearam dezenas deles para que o time pare de discutir percepção e comece a apontar problema com nome próprio.

Para quem  Tech Leads que sentem mas não nomeiam Leitura  ~5 min Funil  Awareness → Consideration

What this article explores:

  • A diferença entre bug, code smell e estilo — três categorias frequentemente confundidas
  • O catálogo de smells estruturais (Long Method, Feature Envy, Data Clumps, Shotgun Surgery e outros)
  • Smells idiomáticos por linguagem — Java, TypeScript, Python, Go
  • Estudo de caso: Feature Envy refatorado lado-a-lado
  • O que análise estática captura — e o que ainda exige revisão humana
  • Como Code Smells produzem perda de familiaridade e medo de alterar
  • O ganho de pipeline ao detectar smells em pre-commit hook
  • Plano operacional em 4 passos para começar hoje
  • Cinco pontos-chave para levar embora
§ 1 Cena

Você revisa o PR. Vê uma classe que recebe três objetos e chama getters de todos eles para fazer a operação. Algo te incomoda. Você comenta: "esse método está esquisito, podia estar em outro lugar". O autor responde: "Funciona, passa nos testes; qual o problema?"

Você não consegue articular o problema. Sai da revisão com sensação ruim. Aprova mesmo assim.

O problema tem nome. Isso se chama Feature Envy. E é um dos dezenas de padrões catalogados por Kent Beck e Martin Fowler em Refactoring (1999) para resolver exatamente esse tipo de discussão: dar nome ao que o reviewer experiente sente, mas não consegue explicar.

A diferença entre bug, smell, e estilo

Para usar a métrica corretamente, é fundamental distinguir três categorias que costumam ser confundidas:

Categoria O que é Exemplo
Bug Erro de execução. O código faz algo que não deveria. if (x != 5) quando o intent era if (x == 5)
Code Smell Padrão de design ruim. Funciona, mas tem alta probabilidade de virar um bug ou de ser doloroso de manter. Método com 200 linhas; classe que invade outra
Estilo Convenção estética. Não tem impacto técnico real. Nomear userId ou user_id; chaves em linha nova
§ 2 Catálogo

Linters detectam todos os três. A diferença está no nível de gravidade. Code Smell é a categoria do meio — não te quebra hoje, mas te quebra em três meses se você ignorar.

As duas frentes catalogadas

A análise estática moderna divide os Code Smells em duas categorias. A primeira é dos smells estruturais — problemas genéricos de design, independentes de linguagem. Existem mais de 30 tipos fundamentais. Os mais comuns:

Estrutural
Long Method
Método com mais de N linhas (geralmente 30–50). Sinal de responsabilidade não decomposta.
Estrutural
Long Parameter List
Função recebendo 6+ parâmetros. Indica que o conjunto deveria virar um objeto.
Estrutural
Large Class
Classe com muitos métodos ou responsabilidades. Violação do princípio de responsabilidade única.
Estrutural
Feature Envy
Método que usa mais dados de outra classe do que da sua própria. Comportamento no lugar errado.
Estrutural
Data Clumps
Grupo de variáveis que sempre aparecem juntas. Deveriam estar encapsuladas em um objeto.
Estrutural
Switch Statements
Switch grande sobre tipo. Geralmente, sinal de polimorfismo perdido.
Estrutural
Shotgun Surgery
Uma mudança simples exige alterar muitos arquivos. Acoplamento difuso.
Estrutural
Primitive Obsession
Uso excessivo de tipos primitivos em que objetos pequenos seriam mais expressivos.
§ 3 Idiomáticos

A segunda frente: smells idiomáticos — convenções específicas de linguagem. Centenas de regras por linguagem.

  • Java: usar Optional em vez de retornar null; preferir composição sobre herança
  • TypeScript: evitar any; usar readonly quando possível
  • Python: usar list comprehension em vez de map/filter manual; preferir f-strings
  • Go: tratar erros explicitamente; evitar interface{} desnecessário

Estudo de caso: Feature Envy

O Feature Envy é o exemplo mais didático porque captura exatamente aquilo que o reviewer experiente sente sem conseguir nomear.

− Antes · Feature EnvySmell
class OrderProcessor {
  calculateDiscount(customer, order) {
    if (customer.getTier() === 'GOLD' &&
        customer.getYearsActive() > 2) {
      if (order.getValue() > 1000 &&
          order.getItems().length > 5) {
        return order.getValue() * 0.15;
      }
    }
    return 0;
  }
}
+ Depois · na classe certaLimpo
class Order {
  private qualifiesForDiscount(customer) {
    return customer.isGoldVeteran() &&
           this.value > 1000 &&
           this.items.length > 5;
  }

// Metodo pode ser chamado direto na
// instancia da order, sem expor getters.
calculateDiscount(customer) { return this.qualifiesForDiscount(customer) ? this.value * 0.15 : 0; } }
§ 4 Análise

Olhe a função: ela recebe customer e order, mas não usa nada da própria classe OrderProcessor. Todos os getters são de objetos externos. Isso é "comportamento no lugar errado" — o método tem mais interesse nos dados de order (e secundariamente customer) do que nos seus próprios.

Na versão refatorada, a lógica vive em Order (que conhece seus próprios dados) e usa um método auxiliar de Customer (isGoldVeteran()) que encapsula a regra de elegibilidade. Os getters expostos para fora desaparecem. O código fica mais difícil de quebrar do lado de fora.

O que análise estática captura — e o que não

A análise estática é excelente para detectar smells estruturais e idiomáticos. Ferramentas modernas de análise estática (ESLint, Prettier, RuboCop, Pylint, Checkstyle e a plataforma SQA da Codurance, que integra todas as cinco métricas da série) detectam Long Method, Feature Envy, parâmetros demais, padrões idiomáticos errados — em segundos, em milhões de linhas de código.

O que análise estática não captura bem:

  • Nomenclatura ruim. Nomes que não refletem o domínio do negócio. Para isso, ainda precisa de revisão humana ou de IA com contexto.
  • Acoplamento conceitual. Duas classes que parecem independentes, mas mudam sempre juntas porque, conceitualmente, representam a mesma coisa.
  • Modelagem de domínio errada. Quando a estrutura de classes não reflete a realidade do negócio.
O que isso libera

Análise estática libera tempo dos reviewers — em vez de gastar atenção apontando "esse método está muito longo", eles podem focar em "essa modelagem está errada". Use o linter para o que é mecânico; use o humano para o que é conceitual.

Code Smells acumulados produzem perda de familiaridade e medo de alterar. Não é estética. É previsibilidade operacional.

§ 5 Efeito Sistêmico

Familiaridade e medo

Code Smells acumulados produzem dois efeitos previsíveis:

Perda de familiaridade. Cada autor escreve no seu estilo. Sem padrão, cada arquivo vira uma surpresa. Onboarding fica longo. Trocar de área do sistema vira um projeto.

Medo de alterar. Quando o código está cheio de Feature Envy, Long Method, Shotgun Surgery, qualquer mudança tem efeito colateral imprevisível. O time desenvolve uma cautela excessiva — e essa cautela vira lentidão.

Eliminar smells sistematicamente impõe um padrão. O resultado é o "código que parece escrito por uma única pessoa" mesmo num time de 50 devs. Não é estética. É previsibilidade operacional.

Pre-test gate: o ganho de pipeline

Code Smells são detectados antes dos testes rodarem — direto no commit, no pre-commit hook ou no PR check. Isso significa:

  • Código com smell crítico nem entra no pipeline. Falha rápido, antes de gastar minutos de CI.
  • O reviewer não precisa apontar coisas que o linter já pega. PR review fica focado em conteúdo.
  • O padrão é aplicado por máquina, não por um chefe. Tira a política da equação.
§ 6 IA Generativa

O impacto dos Code Smells no uso de IA

A IA generativa reproduz os smells do código no qual opera. Não corrige Long Method — continua adicionando à função existente, porque é mais barato pra ela do que decompor responsabilidades. Não corrige Feature Envy — replica o padrão porque não conhece o domínio do negócio. Não evita smells idiomáticos como any em TypeScript ou null em Java — usa o que já está acostumada a ver na base.

O que acontece em código com smells acumulados + IA

  • Comportamento adicionado nos lugares errados. A IA replica Feature Envy: continua acessando getters de outras classes em vez de mover o método para o lugar certo.
  • Aumento de duplicação. Sem modularização que sinalize "a regra de negócio vive aqui", o LLM não sabe onde reutilizar. Cria uma nova função, copia o padrão local. O smell se propaga.
  • Maior chance de bugs introduzidos. Quando a base está cheia de smells, o contexto que a IA precisa carregar pra entender o impacto da mudança fica enorme. Ela perde precisão.
  • Testes automatizados também ficam complexos. Tests gerados pela IA herdam a fragilidade da base — refletem smells em vez de verificar comportamento. A manutenção do test suite vira um problema à parte.
A boa notícia

Código limpo de smells, com modularização clara e padrões consistentes, faz a IA trabalhar com você. Ela reconhece convenções, reutiliza componentes existentes e gera código que se encaixa. A análise estática contínua de smells virou pré-condição para extrair valor de IA generativa.

O que fazer agora
Plano operacional · 4 passos
  1. 1Adote um linter por linguagem. ESLint (JS/TS), RuboCop (Ruby), Pylint/Ruff (Python), golangci-lint (Go), Detekt/Ktlint (Kotlin), Checkstyle/SpotBugs (Java).
  2. 2Configure no pre-commit hook. Não no CI — o feedback no commit é instantâneo, no CI é tardio.
  3. 3Comece com regras default. Não customize tudo no dia 1. Use o catálogo padrão e ajuste só onde fizer barulho real.
  4. 4Tolerância zero para novos smells. Os antigos podem virar baseline. Mas qualquer novo PR não pode introduzir smell crítico.
Resumo · Pontos-chave
Cinco frases para levar embora.
  • Code Smells são padrões de design ruins catalogados. Não são bugs, não são estilo.
  • Beck e Fowler nomearam para tirar a discussão da percepção e levar para o concreto.
  • Estruturais (genéricos) + idiomáticos (por linguagem) — duas frentes complementares.
  • Análise estática captura estrutura e sintaxe. Nomenclatura e modelagem ainda exigem humano.
  • O efeito sistêmico é familiaridade e redução de medo. Não é estética — é velocidade.
Próximo passo

Code Smells aumentam a probabilidade de bugs. O próximo post da série fala de outra métrica que detecta o bug antes de ele acontecer — Bug Analysis encontra erros lógicos por análise estática, sem precisar executar uma linha de código.

Bug Analysis→

How Codurance can help

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 análise estática em pre-commit hooks, definir thresholds de smells por severidade e estabelecer rituais de refatoração que mantêm a propriedade de "familiaridade" no código ao longo do tempo.

Se você quer aplicar essas práticas no seu time, entre em contato hoje.