SOLID sem mistério

Como escrever código mais simples, evolutivo e resistente a mudanças

Se você já escreve código orientado a objetos, em algum momento vai ouvir alguém falar de SOLID. Normalmente vem como um nome meio misterioso, que parece coisa avançada demais.

Na prática, SOLID é bem mais simples do que parece.

Ele não é um framework que você instala, nem uma arquitetura que você precisa seguir à risca. SOLID é só um guia de boas ideias. São cinco princípios criados para ajudar a tomar decisões melhores ao escrever código.

A ideia é simples. Evitar código frágil, difícil de entender e que quebra toda vez que algo muda. Seguindo esses princípios, o código tende a ficar mais organizado, mais fácil de testar e muito mais fácil de evoluir com o tempo.

Vou usar as ilustraçoes do artigo “The S.O.L.I.D Principles in Pictures” de Ugonna Thelma, de forma traduzidas, para compor esse artigo.

Resumo rápido (TL;DR)

  • S: Uma classe, uma responsabilidade.
  • O: Estenda o comportamento, não altere o código original.
  • L: Subclasses devem honrar o contrato da classe pai.
  • I: Interfaces pequenas e focadas em vez de “interfaces monstro”.
  • D: Dependa de abstrações (interfaces) e não de implementações.

1. S — Single Responsibility (Responsabilidade Única)

“Uma classe deve ter um único motivo para mudar.”

  • A Ideia: Cada unidade de código deve fazer apenas uma coisa e fazê-la bem. Se uma classe valida dados, salva no banco e envia e-mails, ela tem três motivos distintos para ser alterada.
  • Sinal de Alerta: Se você descreve uma classe usando vários “e” (ex: “esta classe calcula o bônus e gera o log”), você provavelmente violou este princípio.
  • Benefício: Mudanças localizadas e baixo risco de efeitos colaterais.

2. O — Open-Closed (Aberto/Fechado)

“Aberto para extensão, mas fechado para modificação.”

  • A Ideia: Você deve conseguir adicionar novos comportamentos sem mexer no código que já está funcionando. Isso evita causar bugs onde a Classe estiver sendo usada. Então, se você deseja que a Classe execute mais funções, a abordagem ideal é acrescentar essas funções e NÃO alterar às que já existem.
  • Exemplo simples: Sempre que surge um novo tipo de regra e você precisa: abrir uma classe antiga, adicionar mais um if ou switch, O princípio está sendo violado.
  • A Prática: Em vez de encher uma classe de if ou switch sempre que surge uma nova regra, utilize abstrações. Crie novas classes que estendam o comportamento base.
  • Benefício: Código estável e evolução previsível (você não quebra o que já está em produção).

3. L — Liskov Substitution (Substituição de Liskov)

“Subclasses devem ser substituíveis por suas classes base.”

  • A Ideia: Esse princípio busca impor consistência para que a Classe pai ou sua Classe filha possam ser usadas da mesma maneira sem erros. Se um código funciona com a classe pai, ele deve funcionar com qualquer filha, sem precisar de tratamentos especiais. Nesse caso, a Classe filha deve conseguir fazer tudo o que a Classe pai pode fazer. (esse processo é chamado de Herança)
  • Exemplo simples: A imagem mostra que a classe pai entrega café (pode ser qualquer tipo de café). Portanto, é aceitável que a Classe filha entregue Cappucino, porque é um tipo específico de Café. Mas, por exemplo, NÃO seria aceitável entregar Água!
  • Sinal de Alerta: Subclasses que lançam exceções do tipo “Não implementado” ou que alteram drasticamente a regra de negócio da classe pai. Provavelmente a herança está errada.
  • Benefício: Contratos claros, polimorfismo confiável e menos bugs silenciosos.

4. I — Interface Segregation (Segregação de Interface)

“Interfaces específicas são melhores que interfaces genéricas.”

  • A Ideia: Esse princípio busca dividir um conjunto de ações em conjuntos menores para a Classe executar SOMENTE as ações que precisa. É um desperdício quando uma Classe é obrigada a executar ações inúteis. Além disso, pode produzir bugs inesperados se essa Classe não tiver a capacidade de executar essas ações. É melhor ter várias interfaces pequenas e focadas do que uma “interface monstro”.
  • A Prática: Uma Classe deve realizar apenas as ações necessárias para cumprir seu papel. Qualquer outra ação deve ser removida completamente ou movida para outro lugar (caso possa ser usada por outra Classe no futuro).
  • Benefício: Código mais expressivo, menor acoplamento e implementações muito mais simples.

5. D — Dependency Inversion (Inversão de Dependência)

“Dependa de abstrações, não de implementações.”

  • A Ideia: Código de alto nível (regras de negócio) não deve conhecer detalhes de baixo nível. (bancos de dados, APIs externas). Ambos devem depender de interfaces.
  • A Prática: Sua regra de negócio não deve criar o objeto do banco de dados. Ela deve receber um objeto que respeite uma interface (Injeção de Dependência). Não importa se o banco é MySQL ou MongoDB, a regra de negócio permanece a mesma.
  • Benefício: Facilidade extrema para trocar tecnologias e realizar testes unitários (facilita o uso de Mocks), menor acoplamento.

Como os princípios se conectam

Os princípios SOLID não funcionam isoladamente.

  • S e I mantêm o código pequeno e com propósito claro.
  • O e D permitem que o sistema cresça sem precisar de “cirurgias” no código antigo.
  • L garante que as abstrações sejam seguras.

Juntos, eles combatem o crescimento desordenado do sistema.


Um erro comum ao aprender SOLID

Tentar aplicar todos os princípios desde o primeiro dia. SOLID não é sobre perfeição. É sobre direção.

O SOLID serve para combater a complexidade, não para criá-la. Comece simples (S), entenda as interfaces (I) e, conforme o sistema crescer, aplique os demais para organizar a estrutura.

Aplicar um pouco melhor hoje já reduz a dívida de amanhã.


Ordem sugerida para ensino ou aprendizado

  1. Comece pelo S
  2. Avance para o I
  3. Introduza O e D com exemplos reais
  4. Apresente L depois que herança fizer sentido

Essa progressão costuma ser mais natural e menos abstrata.


Conclusão

SOLID não é sobre escrever mais código, é sobre escrever código que resiste ao tempo. Quando bem aplicado, o ato de alterar um sistema deixa de ser um evento perigoso e passa a ser uma tarefa rotineira e segura.

“E tu? Qual destes princípios achas mais difícil de aplicar no dia a dia? Partilha a tua experiência nos comentários!”