“`html
SOLID na prática
Princípios SOLID aplicados no mundo real
Eu uso SOLID como um checklist de decisões — não como burocracia.
A ideia é transformar código “funcionando” em código evolutivo sem virar uma bola de neve.
S — Single Responsibility Separar motivos de mudança
No mundo real, a falha mais comum não é “classes enormes” apenas por tamanho.
O problema é quando uma mesma classe muda por motivos diferentes.
Exemplo: a mesma classe decide negócio, chama API externa, monta payload e trata logs.
Regra prática que eu sigo: se eu consigo descrever “por que essa classe precisaria mudar”
em duas frases diferentes, provavelmente ela deveria ser separada.
- Camadas de responsabilidade: domínio decide “o que”, aplicação coordena “como”, infraestrutura executa “com que tecnologia”.
- Separar formatação: DTOs/mapeamentos não devem estar misturados com regras de cálculo.
- Testabilidade: quando a classe tem dependências externas, eu isolo o acesso para testar a lógica sem rede, disco ou banco.
Resultado: você reduz o acoplamento e diminui o custo de alteração.
Em vez de “arrumar X e quebrar Y”, você passa a mudar uma coisa por vez com impacto controlado.
O — Open/Closed Estender sem editar o que já funciona
Open/Closed, na prática, é sobre estabilizar pontos do código.
Eu separo um “contrato” do comportamento, para que novas variações entrem via implementação.
Onde isso aparece com força:
gateways de pagamento, estratégias de preço, políticas de elegibilidade, regras de cálculo por tipo de cliente.
-
Interfaces e contratos: “o que fazer” vira uma abstração.
“como fazer” vira implementações separadas. -
Orquestração onde precisa existir: o código que coordena chama a interface,
em vez de ficar cheio deif/elsepor tipo. -
Registro de implementações: mesmo quando há um lugar central, eu evito editar lógica do domínio para cada novo caso.
Novas regras entram como novas classes.
O benefício aparece no seu roadmap: novas exigências deixam de ser “edições em cascata”
e viram “adições previsíveis”.
L — Liskov Substitution Herança que não trai o contrato
Esse princípio costuma ser ignorado quando a equipe usa herança como atalho.
Liskov exige que qualquer substituição por subtipo preserve o comportamento esperado.
Em linguagem simples: se uma classe base diz “funciona assim”, a subclasse deve respeitar as regras,
não pode reduzir garantias nem mudar o significado dos retornos.
- Evite subclasses que quebram invariantes (ex.: sobrescrevem método para lançar exceções em casos que antes funcionavam).
-
Cuidado com “contratos” base que escondem suposições.
Se a base permite qualquer entrada e a subclasse não, você quebrou LSP. - Se houver diferença real de modelo, prefira composição e estratégias a heranças forçadas.
Quando LSP é respeitado, seus testes ficam mais confiáveis e suas refatorações menos traumáticas.
D — Dependency Inversion Depender de abstrações, não de detalhes
Dependency Inversion é onde o “SOLID” vira entrega.
Na prática, eu tento garantir que regras de negócio não dependam diretamente de APIs,
bibliotecas específicas ou motores de persistência.
O padrão mental que funciona:
o domínio e a aplicação definem contratos; a infraestrutura implementa.
- Mensagens e repositórios por interface: o serviço usa uma abstração para salvar/ler, sem saber o banco.
- Clientes externos: gateway/adapter por contrato, para trocar provedor sem reescrever o fluxo.
- Sem “new” no meio do negócio: criação de dependências fica fora (camada de montagem/boot).
Exemplo prático Pedido com regras extensíveis e dependências invertidas
Considere um cenário comum: calcular desconto e emitir nota.
Eu quero adicionar novas regras de desconto e trocar o provedor de emissão sem tocar no fluxo principal.
A seguir, um exemplo simplificado mostrando como SOLID “encaixa”.
// Contratos (DIP + OCP)
public interface DiscountPolicy {
boolean supports(Pedido pedido);
Money apply(Pedido pedido);
}
public interface InvoiceIssuer {
void issue(Invoice invoice);
}
public interface PedidoRepository {
Pedido getById(String id);
void save(Pedido pedido);
}
// Regra de negócio (S: uma responsabilidade; O: extensão por implementação)
public final class PedidoService {
private final PedidoRepository repo;
private final java.util.List<DiscountPolicy> policies;
private final InvoiceIssuer issuer;
public PedidoService(
PedidoRepository repo,
java.util.List<DiscountPolicy> policies,
InvoiceIssuer issuer
) {
this.repo = repo;
this.policies = policies;
this.issuer = issuer;
}
public void processar(String pedidoId) {
Pedido pedido = repo.getById(pedidoId);
// Open/Closed: novas políticas entram como novas classes
Money totalDesconto = Money.zero();
for (DiscountPolicy policy : policies) {
if (policy.supports(pedido)) {
totalDesconto = totalDesconto.plus(policy.apply(pedido));
}
}
pedido.aplicarDesconto(totalDesconto);
repo.save(pedido);
// Fluxo não sabe “como” emite, só usa o contrato
Invoice invoice = Invoice.from(pedido);
issuer.issue(invoice);
}
}
// Extensões: adiciona regra sem editar PedidoService (OCP)
public final class DescontoClienteFiel implements DiscountPolicy {
public boolean supports(Pedido pedido) {
return pedido.cliente().isFiel();
}
public Money apply(Pedido pedido) {
return pedido.valor().multiply(0.10);
}
}
// Exemplo de implementação de infraestrutura (DIP)
public final class IssuerProviderX implements InvoiceIssuer {
public void issue(Invoice invoice) {
// chama API do provedor X e trata detalhes técnicos
}
}
Nota sobre Liskov: eu não forcei herança. Em vez disso, usei implementações de
DiscountPolicy. Isso reduz o risco de subtipo violar comportamento.
Próximo passo: aplicar em um caso real do seu projeto
Se você gostou dessa visão, continua comigo nos próximos posts: eu trago padrões de organização,
estratégias para reduzir acoplamento e exemplos práticos de refatoração com impacto mínimo.
Dica rápida
Escolha uma classe “difícil” do seu projeto e responda:
por que ela muda? Se a resposta tiver mais de um motivo, você já achou o primeiro ponto para aplicar SOLID.
“`
Sou Apaixonado pela programação e estou trilhando o caminho de ter cada diz mais conhecimento e trazer toda minha experiência vinda do Design para a programação resultando em layouts incríveis e idéias inovadoras! Conecte-se Comigo!