← Blog

SOLID sem dogma: quando o princípio ajuda e quando a cerimônia atrapalha

SOLID vira religião fácil. Alguém cita o acrônimo na revisão, nasce uma interface para cada classe concreta, e o PR fica maior do que a regra de negócio. O princípio não é o problema. O uso como distintivo é.

Cada letra existe para baratear um tipo de mudança. Se essa mudança não está no horizonte, a cerimônia é custo antecipado. O trabalho do desenho é reconhecer o eixo que realmente varia — e parar ali.

S: uma razão para mudar

Responsabilidade única não significa “uma classe, um método”. Significa um motivo de alteração. Pedido que calcula frete, emite NF-e, envia e-mail e grava auditoria vai mudar por quatro times. Cada hotfix em e-mail arrisca o cálculo.

Ajuda quando dois eixos já se atropelam: persistência misturada com regra, relatório misturado com comando, parser misturado com política. Separar devolve testes e donos claros.

Atrapalha quando você fatia demais cedo. PedidoRepository, PedidoRepositoryInterface, PedidoFactory, PedidoService, PedidoServiceImpl para um CRUD de três campos não é coesão. É labirinto. Uma classe pequena que persiste e valida o óbvio ainda pode ter uma razão só: “este agregado de pedido”.

O: aberto a extensão, fechado a edição

Aberto/fechado brilha no switch que cresce a cada tipo novo. Pontuação de curso, regra de frete, formato de exportação: cada case novo toca código antigo e reabre risco. Polimorfismo ou uma tabela de estratégias deixa o núcleo quieto.

Ajuda quando o tipo novo é frequente e o núcleo é estável. Você já errou duas vezes no mesmo if. O padrão apareceu.

Atrapalha quando há um único tipo e uma previsão vaga de “no futuro”. Interface, factory e plugin para uma política só é teatro. Também atrapalha quando a variação não é tipo, é dado: se o que muda é alíquota, configuração vence hierarquia.

L: substituir sem surpresa

Liskov pede que o subtipo honre o contrato do pai. Retangulo com Quadrado que quebra setLargura é o exemplo clássico porque a herança mentiu sobre o comportamento. Em API, um RepositorioArquivo que silencia erro onde o pai lança exceção também mente.

Ajuda quando você usa herança de comportamento e o cliente depende do contrato. Testes do tipo base devem passar no subtipo.

Atrapalha quando a herança era preguiça. Se o “é um” não se sustenta, composição custa menos do que forçar a árvore a obedecer Liskov. Não invente superclasse para depois sofrer no substituto.

I: interfaces que o cliente usa

Segregação de interface ataca o método que a classe implementa “porque a interface exige” e depois lança UnsupportedOperation. Worker que só consome mensagem não deveria assinar publicar. Tela que só lê pedido não deveria depender de cancelar.

Ajuda quando clientes diferentes puxam o mesmo contrato gordo e travam uns aos outros. Fatia o contrato, os testes ficam honestos.

Atrapalha quando cada método vira uma interface de um método e o construtor recebe oito dependências. Segregação não é atomizar. É não forçar o cliente a conhecer o que ele não usa.

D: depender de abstração no ponto de variação

Inversão de dependência não é “toda classe tem interface”. É: o núcleo não conhece o detalhe instável. A regra de cobrança não instancia o SDK do gateway. O caso de uso não importa o cliente HTTP concreto.

Ajuda quando o detalhe muda — provedor de e-mail, storage, gateway — ou quando o teste precisa de dublê. O domínio permanece legível.

Atrapalha quando a abstração só tem uma implementação e não há teste que a use. IUsuarioRepository copiando 1:1 o UsuarioRepository só para “ficar SOLID” adiciona arquivo e não adiciona liberdade. Extraia a abstração no momento em que o segundo caminho aparece, ou quando o teste já está pedindo.

flowchart TD
  A[Mudança pedida] --> B{Qual eixo varia?}
  B -->|Vários motivos no mesmo tipo| S[Separar responsabilidade]
  B -->|Tipo novo frequente| O[Estender sem editar núcleo]
  B -->|Subtipo quebra contrato| L[Rever herança]
  B -->|Cliente força método inútil| I[Fatiar contrato]
  B -->|Detalhe instável no núcleo| D[Inverter dependência]
  B -->|Variação inexistente| X[Não adicionar cerimônia]
  classDef ouro fill:#FBF5E4,stroke:#C9A227,color:#0B1F18,stroke-width:1.4px
  classDef verde fill:#F3FAF7,stroke:#1E7A57,color:#0B1F18,stroke-width:1.4px
  classDef fim fill:#14513B,stroke:#0F3328,color:#FBFAF6,stroke-width:1.4px
  class A,B ouro
  class S,O,L,I,D verde
  class X fim

Como usar na revisão sem virar polícia

A pergunta útil não é “isso viola SOLID?”. É “qual mudança ficou cara por causa deste desenho?”. Se ninguém aponta uma mudança, o comentário é gosto. Se a mudança é real — novo meio de pagamento na sexta, novo relatório na segunda —, o princípio vira instrumento.

SOLID convive com código pequeno. Um script de 40 linhas não precisa dos cinco. Um módulo de faturamento que já sofreu três vezes no mesmo if precisa de um. Princípio é compressão de experiência, não checklist de PR.

Letra Quando ajuda Quando a cerimônia dói
S Dois times mudam o mesmo arquivo por razões distintas Classe minúscula fatiada em “camadas” vazias
O Terceiro case no mesmo switch em três meses Hierarquia para um único tipo
L Herança de comportamento com clientes reais Superclasse inventada para reusar dois campos
I Interface gorda com métodos throw Uma interface por método sem cliente diferente
D Detalhe de I/O no meio da regra Interface-espelho com uma implementação só

Um teste de honestidade

Pegue a última interface que você criou. Responda:

  1. Qual variação ela protege?
  2. Já existe um segundo caminho, ou só o “talvez”?
  3. O teste usa a abstração de verdade?
  4. Se eu apagar a interface e depender do concreto, o que quebra além do orgulho?

Se a resposta a (2) e (3) for não, a interface está adiantada. Adiar não é preguiça. É recusar custo de navegação sem benefício de mudança.

O catálogo de princípios não substitui o problema. SOLID bem usado deixa a próxima alteração local. SOLID de cartaz deixa o repositório cheio de nomes e vazio de decisão.

Quando o princípio vira checklist, o código piora. Na Programming One cada regra entra quando o projeto precisa dela — o mesmo critério deste texto.

Leia também: Clean Code: nomes, funções e o custo da pressa e Design patterns: o catálogo não substitui o problema.

#SOLID#Design#OOP#Arquitetura

Thiago Nogueira

Autor de A Caixa Mágica e das séries Programming One e AI One na Editora Pensar Bem.

Capa de Python One

Python One

Do primeiro print à API REST em produção.