Code smells: explicação

Publicado 13/07/2026
Close-up extremo do rosto de um homem irritado
By Dave Bergmann

“Code smell” (mau cheiro no código) é um termo informal usado pelos programadores para descrever padrões de design de software comuns a código ruim. Os code smells são mais bem compreendidos não como bugs ou defeitos em si, mas como sinais de alerta de baixa qualidade do código.

O termo “code smell” foi cunhado por Kent Beck e popularizado no seminal livro de 1999 que ele coescreveu com Martin Fowler, Refactoring: Improving the Design of Existing Code, especificamente, no capítulo intitulado “Bad Smells in Code”. O próprio Fowler define de forma sucinta um code smell como “um indício superficial que normalmente corresponde a um problema mais profundo no sistema”.1

Diferentemente de um bug de software de verdade, um code smell não impede que o código-fonte seja compilado, executado e cumpra a função desejada, nem sua presença indica sempre um problema real. Imagine entrar em casa e sentir um cheiro estranho ou de mofo. Esse cheiro pode vir de um alimento estragado na sua geladeira ou do lixo que precisa ser levado para fora; de forma mais grave, pode vir de mofo ou de algo apodrecendo dentro das paredes, mas também pode vir simplesmente de um queijo bem forte, perfeitamente seguro para comer. De todo modo, o cheiro justifica uma inspeção mais atenta.

Para um engenheiro de software experiente, certos padrões no código simplesmente não “cheiram” bem. Com o tempo, a pessoa passa a associar instintivamente a presença deles a certas complicações, ineficiências ou problemas futuros. Nomear e popularizar code smells específicos facilita a familiaridade com esses padrões contraproducentes (ou “antipadrões”) e com os princípios de design que eles violam. Essa familiaridade, por sua vez, aumenta a probabilidade de que esses antipadrões sejam notados e corrigidos durante a revisão de código. Como afirma Fowler, "um cheiro é, por definição, algo que é fácil de detectar, ou farejável".

Os code smells, se não forem tratados, são grandes responsáveis pela dívida técnica. Como afirma um estudo, 75% dos defeitos encontrados em revisões de código não afetam a execução do programa, mas “afetam a evolutibilidade do software”.2 Mesmo que um determinado antipadrão ou mau hábito não cause um bug hoje, ele aumenta significativamente o risco de que bugs, travamentos ou vulnerabilidades de segurança na sua base de código surjam mais tarde . No mínimo, a presença de code smells conhecidos reduz a legibilidade e a manutenibilidade do seu código, tornando-o mais difícil de entender, atualizar e melhorar.

Tipos de code smells

Embora muitos code smells comuns continuem sendo conhecidos pelos nomes cunhados por Beck e Fowler em Refactoring, não existe uma lista única, canônica e universalmente aceita de code smells. Mas se um dado code smell deve ser chamado por um nome ou por outro, ou ser categorizado como um antipadrão próprio em vez de um subtipo de outro, é, em grande medida, irrelevante. O que importa é se o nome e a descrição de um code smell são claros e intuitivos o suficiente para ajudar as equipes de desenvolvimento de software a compartilhar e aplicar princípios de design produtivos.

Da mesma forma, não há uma taxonomia universalmente aceita para as diferentes categorias de code smells. Este artigo se baseia principalmente na taxonomia proposta por Jerzyk e Madeyski em 2023.3 As conclusões deles foram publicadas no útil catálogo mantido em codesmells.org, que fornece contexto adicional, exemplos de código e técnicas de refatoração adequadas para cada um.

Jerzyk e Madeyski observam que a taxonomia de code smells mais frequentemente referenciada segue os cinco agrupamentos propostos por Mäntylä e Lassenius em 2006, que categorizaram os 22 code smells apresentados por Fowler e Beck (e mais um dos próprios autores) em cinco agrupamentos distintos: Bloaters, Object-Orientation Abusers, Change Preventers, Dispensables e Couplers.4 Após sua própria tentativa de uma revisão exaustiva tanto da literatura formalmente publicada quanto do “material cinzento” (como blogs, fóruns e wikis), Jerzyk e Madeyski catalogaram 56 code smells diferentes em 9 agrupamentos (que incluem os 5 citados anteriormente neste parágrafo).

Embora esta seção siga em grande parte a estrutura de 9 categorias que eles propuseram, é importante notar que tais agrupamentos são informais e subjetivos: a taxonomia mais útil é aquela que você achar mais intuitiva. Compreender os diferentes tipos de complicações ou ineficiências que os code smells podem introduzir oferece uma noção mais significativa dos code smells do que a memorização mecânica de smells individuais. Como Mäntylä formula, “com uma longa lista corrida de code smells, é fácil perder a visão do todo”.5

Bloaters

Os bloaters são code smells que muitas vezes fazem métodos, classes ou blocos de código crescerem tanto que se tornam difíceis de gerenciar. Isso reduz a legibilidade e torna o código mais difícil de manter ou modificar.

Exemplos de bloaters incluem:

  • Aglomerados de dados: grupos de variáveis que frequentemente aparecem juntos em todos os lugares.

  • Classe grande: uma classe que tenta fazer muito e contém muitas variáveis, sem coesão.

  • Função longa (método longo): um método que contém muitas linhas de código.

  • Lista de parâmetros longa: funções que exigem muitos argumentos para operar corretamente.

  • Obsessão primitiva: uso de tipos de dados primitivos em vez de objetos pequenos especializados.

Impedidores de mudança

Os change preventers (impedidores de mudança), como o nome sugere, são code smells que tornam mais difícil modificar, ampliar ou desenvolver o software de outras formas. Um caso típico de change preventer é uma estrutura de código que obriga você a fazer uma série de edições em vários lugares só para implementar uma única modificação simples.

Esse tipo de code smell viola o princípio da responsabilidade única (SRP), de Robert C. Martin, que afirma que as mudanças em qualquer módulo de código só devem ter uma única origem. Como Martin sugere em uma postagem de blog sobre o SRP: “Reúna as coisas que mudam pelos mesmos motivos. Separe aquelas que mudam por motivos diferentes.”6

Exemplos de change preventers incluem:

  • Cirurgia com espingarda: implementar uma única mudança exige modificações em muitos módulos dispersos ao mesmo tempo (o que é essencialmente o oposto da classe grande).

  • Mudança divergente: como o inverso da cirurgia com espingarda, implementar uma única mudança exige muitas modificações dentro de uma única classe.

  • Inferno de callbacks: estrutura de código em que muitos métodos ficam aninhados profundamente uns dentro dos outros, ao longo de várias tabulações e chaves, o que obscurece a relação de causa e efeito e torna o código difícil de ler e manter.

Acopladores

Os acopladores são code smells que violam o princípio central de projeto do baixo acoplamento ao criar dependências excessivas entre classes diferentes. Isso reduz a reutilização do código e complica (ou até impede) testes unitários independentes.

Exemplos de acopladores incluem:

  • Inveja de funcionalidade: um método acessa os dados de outro objeto de forma excessiva.

  • Informação privilegiada (também chamada de intimidade inadequada): uma classe usa os campos ou métodos internos de outra classe.

  • Cadeias de mensagens: Uma longa sequência de chamadas de métodos encadeadas entre objetos.

Fornecedores de dados

Os fornecedores de dados processam os dados por meio de muito mais classes ou funções do que o necessário. Isso cria dependências e complexidades desnecessárias, muitas vezes resultando em elementos de código que simplesmente armazenam ou distribuem dados sem fornecer qualquer comportamento significativo.

Exemplos de fornecedores de dados incluem:

  • Intermediário: uma classe cuja única função é delegar tarefas para outras.

  • Dados viajantes: quando os dados “pegam carona” por uma cadeia de métodos que não fazem uso deles.

  • Dados globais: estrutura na qual as variáveis podem ser modificadas de qualquer lugar no código-fonte, tornando cada função no código-fonte suspeita quando algo dá errado.

Dispensáveis

Os dispensáveis são, intuitivamente, elementos de código dispensáveis: sua remoção deixaria a base de código mais limpa e fácil de ler, sem nenhum impacto relevante na funcionalidade geral.

Exemplos de dispensáveis incluem:

  • Comentários: embora os comentários geralmente sejam algo bom, às vezes são usados como um “desodorante” para code smells, explicando em vez de melhorar. Por exemplo, se um comentário descreve o que está acontecendo em um determinado trecho de código, ele está sendo usado para mascarar um código que não é intuitivo ou legível o suficiente por si só. Comentários individuais também podem se tornar redundantes ou desatualizados com o tempo. Comportamentos de comentário mais específicos aparecem em outros code smells.

  • Classe de dados: classes que contêm apenas campos e métodos de acesso, sem nenhum comportamento significativo.

  • Código morto: elementos de código que não são mais executados porque, com o tempo, refatorações e outras modificações os tornaram obsoletos.

  • Código duplicado: estruturas de código idênticas ou muito semelhantes em vários locais.

  • Classe preguiçosa (também conhecida como elemento preguiçoso): classes ou funções que fazem tão pouco que não justificam sua existência.

  • Generalidade especulativa: código desnecessário adicionado para dar suporte a funcionalidades futuras hipotéticas.

Abusadores funcionais

Os abusadores funcionais são exemplos de code smells que ignoram os princípios da programação orientada a objetos, forçando padrões funcionais em uma base de código orientada a objetos.

Exemplos de abusadores funcionais incluem:

  • Loops: usar loops tradicionais em vez de operações modernas de pipeline. Embora Fowler considerasse quase todos os loops como desatualizados, Jerzyk defendeu que os loops imperativos, em particular, são o principal problema.

  • Dados mutáveis: variáveis cujo estado muda inesperadamente, causando efeitos colaterais imprevisíveis.

  • Efeitos colaterais (também conhecidos como funções impuras): métodos que fazem mais do que o seu nome e propósito principal sugerem.

Abusadores léxicos

Abusadores léxicos são code smells que se originam de convenções de nomenclatura inadequadas, formatação inconsistente ou sintaxe enigmática. Em termos simples, são casos em que a redação do código não corresponde de forma intuitiva ao comportamento correspondente, prejudicando a legibilidade.

Exemplos de abusadores léxicos incluem:

  • Número mágico: números sem nome inseridos no código sem explicação ou contexto adequados.

  • Comentário falacioso: comentários que deixaram de ser precisos porque o código ao seu redor foi alterado. Como os comentários não são realmente executados, eles frequentemente escapam de linters e outras verificações automatizadas.

  • Nome misterioso: funções ou variáveis nomeadas de forma inadequada, que ocultam sua verdadeira intenção.

  • Nome de método falacioso: funções cujos nomes induzem ao erro, à luz das convenções e expectativas comuns. Por exemplo, uma função chamada getSomething que na verdade não retorna nada.

Ofuscadores

Os ofuscadores são elementos de código escritos de forma desnecessariamente complexa, rebuscada ou "inteligente", que ocultam a intenção subjacente do código por trás de abstrações desnecessárias. Esses code smells tornam a leitura do código-fonte confusa e, portanto, dificultam que futuros programadores o entendam e o modifiquem conforme necessário.

Exemplos de ofuscadores incluem:

  • Separação vertical: distâncias desnecessariamente grandes entre elementos de código relacionados e relevantes, como uma variável declarada no topo de um método que só é usada 50 linhas depois.

  • Intenção obscura: a categoria mais amplas de funções, variáveis, nomes e números cujo propósito não é intuitivo nem fica claro no contexto.

  • Expressão booleana complexa: fluxos lógicos confusos, como aqueles que contêm dupla negação ou cadeias complexas de IF e IF NOT e AND e AND NOT .

  • Código inteligente: código que funciona, mas que, para situações em que já existem funcionalidades integradas amplamente compreendidas e outras soluções convencionais, as substitui por uma linguagem própria e difícil de acompanhar.

Abusadores orientados a objetos

Abusadores orientados a objetos são code smells que não aplicam de forma completa ou correta os princípios do design orientado a objetos. Por exemplo,as instruções switch são úteis na programação procedural, mas devem ser evitadas na programação orientada a objetos.

Exemplos de abusadores orientados a objetos incluem:

  • Classe alternativa com interfaces diferentes: classes que desempenham funções semelhantes usando nomes de método completamente diferentes.

  • Herança recusada: subclasses que não precisam nem usam os métodos herdados.

  • Instruções switch (também chamadas de Complexidade Condicional ou Switches Repetidos): exatamente a mesma instrução switch duplicada por toda a base de código.

  • Campo temporário: uma variável criada onde muitas vezes não é necessária, geralmente usada apenas em circunstâncias específicas.

Refatoração de code smells

O principal benefício de entender os code smells é que reconhecê-los permite uma refatoração mais eficaz: a prática de atualizar o código-fonte sem modificar seu comportamento ou funcionalidade externos. Arrumar o código com regularidade por meio da refatoração é essencial para reduzir a dívida técnica e viabilizar melhorias e adições rápidas e eficazes à sua base de código ao longo do tempo.

A refatoração pode ser entendida, em grande medida, como o processo de identificar e tratar code smells. Seu objetivo é corrigir problemas antes que eles afetem negativamente a funcionalidade, momento a partir do qual o processo se assemelha mais a depuração do que a refatoração.

Plataformas modernas de engenharia agêntica, como a IBM Bob, frequentemente fornecem sugestões de refatoração automatizadas em tempo real. Por meio de treinamento extensivo sobre code smells comuns no contexto de bases de código reais, em vez da memorização mecânica de definições de code smell, os recursos de refatoração de código com IA dessas plataformas permitem que os desenvolvedores ampliem sua produção sem um aumento correspondente de código gerado por IA difícil de manejar, que será difícil de entender e modificar depois.

Autor

Dave Bergmann

Senior Staff Writer, AI Models

IBM Think

Soluções relacionadas
IBM Bob

Acelere a entrega de software com o IBM® Bob, seu parceiro de IA para desenvolvimento seguro e consciente de intenção.

Explore o IBM Bob
Soluções de IA para desenvolvedores

Desenvolva, implemente e gerencie aplicações de IA mais rápido com ferramentas prontas para empresas.

Explore IA para desenvolvedores
Serviços de modernização de aplicações

Reimagine sistemas legados com modernização inteligente de IA.

Explore os serviços de modernização de aplicações
Dê o próximo passo

Utilize IA generativa e automação avançada para oferecer código pronto para empresas com maior velocidade e consistência. Os modelos do Bob aumentam os conjuntos de habilidades dos desenvolvedores, agilizando os fluxos de trabalho de modernização e simplificando tarefas complexas de desenvolvimento.

  1. Conheça o agente de programação de IA
  2. Explore soluções de IA para desenvolvedores