Code Smells e SOLID
Por que smells e princípios são o mesmo assunto
Seção intitulada “Por que smells e princípios são o mesmo assunto”Code smells são heurísticas — “isto cheira mal, investigue”. SOLID são princípios — “por que cheira mal”. Um é o radar, o outro é a explicação. Quando você aprende a traduzir smell → princípio, o refactoring deixa de ser mecânico e passa a ter direção: você sabe para onde mover o código, porque sabe qual princípio restaurar.
graph LR
S["Code Smell<br/>(sintoma)"] --> P["Princípio SOLID violado<br/>(diagnóstico)"]
P --> R["Técnica de Refactoring<br/>(tratamento)"]
R --> C["Design saudável"]
Mapa smell → princípio → refactoring
Seção intitulada “Mapa smell → princípio → refactoring”| Code smell | Princípio violado | Refactoring que cura |
|---|---|---|
| Large Class / God Class | SRP | Extract Class, Move Method |
| Divergent Change (muda por vários motivos) | SRP | Extract Class por eixo de mudança |
| Shotgun Surgery (uma mudança respinga em N lugares) | OCP | Move Method/Field, consolidar; introduzir abstração |
Switch/instanceof sobre “tipo” repetido |
OCP | Replace Conditional with Polymorphism |
| Refused Bequest (subclasse ignora/rejeita herança) | LSP | Replace Subclass/Superclass with Delegate (na 1ª ed., Replace Inheritance with Delegation) |
UnsupportedOperationException em override |
LSP + ISP | Segregar interface; compor em vez de herdar |
| Interface “gorda” que força métodos vazios | ISP | Quebrar em role interfaces menores |
| Feature Envy (método usa mais dados de outra classe) | SRP (coesão) | Move Method |
new de infraestrutura dentro da regra |
DIP | Introduzir porta + injeção de dependência |
| Primitive Obsession (String/int para CPF, dinheiro) | Coesão de domínio (leva a espalhar regra) | Replace Primitive with Object (→ Value Object) |
O caso especial do modelo anêmico
Seção intitulada “O caso especial do modelo anêmico”O smell mais relevante para quem estuda DDD: entidades só com getters/setters e toda a regra num service gigante. É um combo de violações — SRP (o service acumula responsabilidades de várias entidades) e baixa coesão. O tratamento é mover comportamento de volta para as Entidades e Agregados, transformando o service anêmico num orquestrador fino. Isso também melhora a testabilidade (ver Testabilidade e Arquitetura): lógica na entidade se testa sem mocks.
Do smell ao refactoring com segurança
Seção intitulada “Do smell ao refactoring com segurança”O elo que falta: você não sai refatorando sobre código de produção sem rede. A sequência saudável é smell detectado → teste que fixa o comportamento atual → refactoring → teste verde. Por isso Fundamentos de Refactoring depende de testes, e o passo Refactor do TDD é o momento natural de pagar esses smells enquanto a suíte ainda está verde.
Anti-padrões e erros comuns
Seção intitulada “Anti-padrões e erros comuns”- Caçar smell sem entender o princípio: renomear e extrair no automático pode mover o problema de lugar sem restaurar nenhum princípio. Diagnostique antes.
- Refatorar sem teste: transforma “mudar estrutura preservando comportamento” em “torcer para não quebrar”. Ver Fundamentos de Refactoring.
- Aplicar SOLID de forma dogmática: nem todo switch é violação de OCP; nem toda classe grande fere SRP. O smell precisa doer (mudança frequente, bug recorrente) para justificar o custo do refactoring.
- Confundir Primitive Obsession com over-engineering: criar value object para tudo também é smell. Use onde há regra/invariante.
Relações
Seção intitulada “Relações”- Code Smells · Técnicas de Refactoring · Fundamentos de Refactoring
- SOLID · SRP - Single Responsibility Principle · OCP - Open-Closed Principle · LSP - Liskov Substitution Principle · ISP - Interface Segregation Principle · DIP - Dependency Inversion Principle
- Value Objects · Entidades · Agregados
- Testabilidade e Arquitetura
- Como Tudo se Conecta
Perguntas de revisão
Seção intitulada “Perguntas de revisão”- Por que “Shotgun Surgery” é considerado uma violação de OCP?
Resposta
Porque uma única mudança de requisito obriga a editar muitos pontos espalhados — o oposto de “fechado para modificação”. A cura é consolidar a responsabilidade e introduzir uma abstração que absorva a variação, deixando o sistema aberto para extensão.
- Qual smell mapeia para “Replace Conditional with Polymorphism” e por quê?
Resposta
Switch/instanceof sobre um “tipo” repetido pela base. Ele viola OCP porque cada novo tipo exige editar todos os switches. Polimorfismo move cada ramo para uma subclasse/estratégia, tornando a extensão aditiva.
- Por que o modelo anêmico é um problema de coesão e de testabilidade ao mesmo tempo?
Resposta
A lógica que deveria estar na entidade migra para um service, que acumula responsabilidades (baixa coesão, fere SRP) e passa a exigir muitos mocks para ser testado. Mover o comportamento de volta à entidade resolve ambos.
- Encontrar um smell justifica refatorar imediatamente?
Resposta
Não. Smell é heurística. Só compensa refatorar quando ele dói de fato (mudança frequente, bugs) e há testes cobrindo. Caso contrário pode ser custo sem retorno.