Code Smell no desenvolvimento mobile: o que é, tipos e princípios de correção

Autor: IT Sectr Publicado: 2026-05-13 Tempo de leitura: 9 min

Code Smell é um indicador superficial no código que sinaliza um problema potencial no design ou na arquitetura de uma aplicação. O termo foi cunhado por Kent Beck e popularizado por Martin Fowler no livro “Refactoring: Improving the Design of Existing Code”. De acordo com Martin Fowler, um cheiro no código não significa necessariamente um bug, mas quase sempre indica a necessidade de refatoração para melhorar a manutenibilidade.

Principais Pontos

  • Code Smell — um indicador superficial de um problema no código que não é um erro, mas dificulta a manutenção e o desenvolvimento
  • Long Method — o cheiro mais comum: um método que faz demasiado e precisa ser dividido em vários
  • Large Class — uma classe que viola o Princípio da Responsabilidade Única e contém lógica de diferentes domínios
  • Duplicate Code — fragmentos de código repetidos que exigem correção em múltiplos lugares quando alterados
  • Feature Envy — um método que usa mais dados de outra classe do que da sua própria

O que é Code Smell

Code Smell é uma metáfora para sintomas no código-fonte que com alta probabilidade indicam problemas mais profundos. O termo em si não tem uma definição formal — é uma heurística baseada na experiência dos desenvolvedores. Martin Fowler e Kent Beck sistematizaram pela primeira vez 22 cheiros em 1999 no livro “Refactoring”, e a maioria deles permanece relevante décadas depois.

É importante entender a diferença entre Code Smell e um bug. Um cheiro não é um erro: o código compila, funciona e produz resultados corretos. O problema é que esse código é difícil de ler, modificar e testar. Com o tempo, o custo de cada mudança aumenta e a confiança na correção da refatoração diminui. Ferramentas de análise estática (SonarQube, Detekt, SwiftLint) detetam automaticamente muitos cheiros.

A natureza heurística do Code Smell significa que nem todo método longo precisa ser dividido, e nem toda classe grande requer refatoração. A decisão é tomada pelo desenvolvedor avaliando o contexto: frequência de mudanças, criticidade do módulo, planos de desenvolvimento. Engenheiros experientes sentem um cheiro intuitivamente — o código “cheira mal” mesmo que todas as regras formais sejam seguidas.

Principais tipos de Code Smell

Fowler identificou 22 cheiros agrupados em várias categorias. Para o desenvolvimento mobile, os mais relevantes são os cheiros estruturais, os cheiros de design orientado a objetos e problemas específicos relacionados com limitações da plataforma. Vamos examinar cada grupo com exemplos reais.

Cheiros estruturais

Long Method é o cheiro mais comum em aplicações mobile. Um ecrã de formulário de registo frequentemente contém um único método setupUI com 200+ linhas que cria todas as Views, configura constraints, subscreve eventos e trata erros. Solução: dividir em métodos por blocos lógicos — configureEmailField, configurePasswordField, setupConstraints, bindViewModel.

Large Class — uma Activity ou ViewController responsável pela exibição, navegação, lógica de negócio e interações de rede tudo ao mesmo tempo. Essa classe viola o Princípio da Responsabilidade Única e contém dezenas de campos e métodos. No Android, é frequentemente um Fragment com 1000+ linhas contendo lógica de diferentes ecrãs. Solução: extrair um presenter/ViewModel, mover o código de rede para um repositório e a navegação para um coordenador.

Duplicate Code — copiar blocos idênticos em diferentes partes da aplicação. Um exemplo típico: dois ecrãs exibindo um cartão de produto — no catálogo e nos favoritos. Se a lógica de exibição foi copiada, corrigir um bug num lugar não o corrigirá no outro. Solução: extrair a lógica comum para um componente reutilizável ou extensão.

Cheiros de design orientado a objetos

Feature Envy — um método de uma classe usa intensivamente dados de outra classe. No Android, isso manifesta-se quando uma ViewModel acede diretamente aos campos de um modelo User em vez de chamar um método do modelo. Sinal: se um método pode ser movido para a classe cujos dados usa — mova-o. Switch Statements (cadeias de condições) — uma construção switch ou cadeia if-else que verifica o tipo do objeto. Em vez disso, use polimorfismo ou o padrão strategy.

Data Class — uma classe que apenas armazena dados mas não contém comportamento. As data classes em Kotlin ou estruturas em Swift não são inerentemente um cheiro. O problema surge quando a lógica de negócio que trabalha com esses dados está espalhada pela base de código em vez de encapsulada. Refused Bequest — uma subclasse não usa a maioria dos métodos do pai e sobrepõe-nos com stubs vazios. Sinal de herança incorreta: substitua herança por composição.

Cheiros no desenvolvimento mobile

God Activity / God Fragment — uma Activity ou Fragment que sabe tudo: ciclo de vida, dados, navegação, Permissões, DI. É a classe mais cara de manter numa aplicação. Solução: padrões arquiteturais MVVM, MVI ou Clean Architecture separam responsabilidades. Giant ViewController — o equivalente no iOS, onde um UIViewController contém toda a lógica do ecrã e frequentemente excede 500 linhas.

Hardcoded Resources — strings, cores, tamanhos, URLs de API embutidos diretamente no código. No Android, isso viola o sistema de recursos R; no iOS, NSLocalizedString e Asset Catalog. Correção: mover todas as strings para strings.xml ou Localizable.strings, URLs para um ficheiro de configuração, tamanhos para dimens. Leaking Context — manter uma referência a uma Activity ou ViewController por mais tempo que o próprio componente vive. Causa fugas de memória e crashes. Solução: referências fracas, Jetpack Lifecycle, RxSwift DisposeBag.

CheiroOnde ocorreSolução
Long MethodAndroid/iOSExtract Method, dividir
Large ClassActivity, ViewControllerMVVM, VIPER, Clean Arch
Duplicate CodeQualquer ecrãComponente partilhado, DRY
Feature EnvyViewModel, PresenterMove Method
Leaking ContextAndroidComponentes Lifecycle-aware

Como encontrar Code Smell

Code review é a forma mais fiável de detetar cheiros. O olho humano nota construções não naturais que os analisadores automáticos perdem. A eficácia do code review melhora quando a equipa usa uma lista de verificação de cheiros típicos. Recomenda-se rever não mais de 200–400 linhas de código por sessão — após este limite, a atenção diminui e os cheiros começam a escapar.

Análise estática automatiza a procura de cheiros estruturais. Para Android, as ferramentas padrão são Detekt (Kotlin) e Android Lint; para iOS, SwiftLint e SonarQube. Essas ferramentas encontram métodos longos, classes grandes, código duplicado e muitos outros problemas. É importante ajustar as regras ao projeto — configurações predefinidas são frequentemente demasiado rigorosas ou, pelo contrário, perdem cheiros críticos.

Métricas de código fornecem critérios objetivos: Complexidade Ciclomática (limiar >10 requer atenção), Linhas de Código por Método (limiar >30), Profundidade de Herança (>3 — motivo para pensar). Ferramentas como CodeMetrics (Xcode) e Gradle Metrics Plugin constroem gráficos de mudanças de métricas ao longo do tempo. Se a complexidade de um método cresceu de 5 para 15 após o último commit — é um sinal para refatorar.

kotlin
// Exemplo: método com Complexidade Ciclomática = 7 (acima do limiar 5)
fun processOrder(order: Order) {
    if (order.status == Status.NEW) { /* 10 linhas */ }
    else if (order.status == Status.PAID) { /* 15 linhas */ }
    else if (order.status == Status.SHIPPED) { /* 20 linhas */ }
    else if (order.status == Status.DELIVERED) { /* 8 linhas */ }
    else if (order.status == Status.CANCELLED) { /* 5 linhas */ }
    else { throw IllegalStateException() }
}

// Correção: polimorfismo em vez de switch
interface OrderHandler {
    fun handle(order: Order)
}

A deteção automatizada de cheiros não substitui o code review: os analisadores estáticos apenas encontram problemas estruturais, mas não capturam cheiros semânticos (Feature Envy, Inappropriate Intimacy). A combinação de ferramentas automáticas e revisão humana dá os melhores resultados. Configure o pipeline CI/CD para que as compilações falhem quando os limiares de complexidade ou comprimento de método forem excedidos.

Como corrigir Code Smell

Refatoração é o método principal para eliminar cheiros de código. Fowler descreve dezenas de técnicas de refatoração, cada uma aplicável a um cheiro específico. Extract Method — para métodos longos, Extract Class — para classes grandes, Move Method — para Feature Envy. É importante realizar a refatoração em pequenos passos, mantendo o código funcional após cada alteração.

Testes antes de refatorar são obrigatórios. Se o código não estiver coberto por testes unitários, a refatoração transforma-se em reescrita com resultados desconhecidos. Para código legado sem testes, use Characterization Tests — escreva testes que capturem o comportamento atual, depois refatore. Os testes dão confiança de que a lógica de negócio não foi quebrada após a refatoração.

Gradualidade é a chave para corrigir com sucesso cheiros no desenvolvimento mobile. Não tente reescrever uma God Activity por completo. Primeiro extraia a camada de navegação, depois a camada de dados, depois a lógica de exibição. Cada passo deve ser acompanhado por um commit e execução de testes. Use feature toggles para ativar a refatoração para um subconjunto de utilizadores e reverter se surgirem problemas.

  • Extract Method — dividir um método longo em vários curtos com nomes claros
  • Extract Class — extrair um grupo relacionado de campos e métodos numa classe separada
  • Replace Conditional with Polymorphism — substituir switch por uma hierarquia de classes
  • Introduce Parameter Object — combinar um grupo de parâmetros num objeto
  • Replace Inheritance with Delegation — substituir extends por composição

As ferramentas do IDE automatizam muitas técnicas de refatoração. Android Studio e IntelliJ IDEA oferecem refatorações integradas: Extract Method, Extract Interface, Pull Members Up, Encapsulate Fields. Xcode (a partir da versão 14) melhorou o suporte de refatoração para Swift. O uso de refatorações automáticas reduz o risco de erros em comparação com a cópia manual de código.

Code Smell no desenvolvimento mobile

O desenvolvimento mobile adiciona os seus próprios cheiros específicos relacionados com limitações da plataforma. No Android, isto inclui fugas de Context, cursores não fechados e uso incorreto do Lifecycle. No iOS, ciclos de retenção através de closures, manipulação incorreta de Auto Layout e ViewControllers gigantes. Estes cheiros não só prejudicam a manutenibilidade, como também afetam diretamente o desempenho e a estabilidade da aplicação.

Callback Hell é um cheiro característico para código que trabalha com operações assíncronas. Callbacks aninhados tornam o código ilegível e difícil de depurar. Solução: corrotinas (Kotlin), async/await (Swift 5.5+), RxJava/RxSwift ou Combine. De acordo com Google I/O 2023, projetos que migraram do estilo callback para corrotinas reduziram o número de bugs em 30% e aceleraram a adição de novas funcionalidades.

Platform Coupling — acoplamento forte da lógica de negócio a componentes da plataforma. Testar essa lógica requer iniciar um emulador, o que atrasa o ciclo de feedback. Correção: Clean Architecture separa o código em camadas Domain (Kotlin/Swift puro sem dependências de plataforma) e Data/UI (com dependências de plataforma). A lógica de negócio é testada na JVM sem emulador.

Perguntas Frequentes

Code Smell é a mesma coisa que um bug?

Não — Code Smell não é um erro. O código com cheiro funciona corretamente, mas é difícil de manter, modificar e testar. Um bug é um comportamento incorreto; um cheiro é um aviso sobre potenciais problemas futuros.

Quantos cheiros Martin Fowler identificou?

22 cheiros na segunda edição de “Refactoring” (2019). Entre eles estão Long Method, Large Class, Primitive Obsession, Data Clumps, Switch Statements, Speculative Generality e outros. A comunidade adicionou dezenas de novos cheiros para paradigmas e plataformas modernas.

Qual ferramenta é melhor para encontrar Code Smell?

Uma combinação dá o melhor resultado: Detekt (Android/Kotlin), SwiftLint (iOS), SonarQube (ambos) para análise automática e code review para cheiros semânticos. Nenhuma ferramenta encontra 100% dos problemas — a experiência humana continua a ser decisiva.

Pode-se ignorar Code Smell?

Sim, se o código muda raramente ou será completamente reescrito em breve. No entanto, a acumulação de cheiros transforma-se em dívida técnica: cada nova mudança torna-se mais difícil e o custo de correção cresce exponencialmente.

Existem cheiros específicos para SwiftUI e Jetpack Compose?

Sim — os frameworks declarativos geraram novos cheiros: blocos @State gigantes, manipulação incorreta de renderizações repetidas, recomposição excessiva e falta de Extração em Views separadas. Para SwiftUI, um cheiro típico é Massive View com dezenas de variáveis @State.

Resumo

  • Code Smell — um sinal superficial de um problema profundo no código, não um bug, mas que reduz a manutenibilidade
  • Long Method e Large Class — os cheiros mais comuns no desenvolvimento mobile, exigindo Extract Method e Extract Class
  • Duplicate Code — lógica duplicada que duplica o trabalho a cada mudança
  • Feature Envy e Switch Statements — sinais de distribuição incorreta de responsabilidades entre classes
  • Cheiros específicos — God Activity, Giant ViewController, Leaking Context — únicos das plataformas mobile
  • Refatoração sem testes é perigosa: primeiro Characterization Tests, depois pequenos passos com commits
  • Análise estática (Detekt, SwiftLint) automatiza a deteção mas não substitui o code review

Vamos desenvolver um aplicativo móvel chave na mão

A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.

Discutir o projeto

Leia também