SOLID explicado: os 5 princípios com exemplos práticos

Os princípios SOLID são um conjunto de cinco diretrizes fundamentais de design de software criadas para tornar o código mais compreensível, flexível e manutenível ao longo do tempo. O acrônimo representa os seguintes preceitos: Responsabilidade Única (SRP), Aberto/Fechado (OCP), Substituição de Liskov (LSP), Segregação de Interface (ISP) e Inversão de Dependência (DIP).

Principais Aprendizados

  • O princípio da Responsabilidade Única (SRP) não significa que uma classe deve fazer apenas uma coisa, mas sim que deve ter apenas um motivo (ou ator) para mudar.
  • A aplicação pragmática do SOLID facilita testes automatizados e reduz o acoplamento, mas o uso dogmático pode gerar overengineering e fragmentação excessiva.
  • Inversão de Dependência (DIP) é um princípio arquitetural sobre depender de abstrações, enquanto a Injeção de Dependência (DI) é o padrão usado para alcançar isso.

A Origem e a Evolução do SOLID

É um fato histórico documentado que os cinco princípios que compõem o SOLID foram compilados e apresentados formalmente pelo engenheiro de software Robert C. Martin (o famoso "Uncle Bob") no ano 2000, em seu artigo "Design Principles and Design Patterns", conforme verificado pela Baeldung. No entanto, um detalhe curioso que muitos desconhecem é que o acrônimo "SOLID" não foi criado por ele. Foi Michael Feathers, por volta de 2004, quem notou que as iniciais desses cinco princípios formavam a palavra quando reorganizados.

Para quem está construindo uma base sólida em programação orientada a objetos, dominar esses conceitos é um divisor de águas.

Blocos de montar representando os princípios SOLID

Os 5 Princípios SOLID Explicados com Exemplos Práticos

S - Single Responsibility Principle (Princípio da Responsabilidade Única)

Existe um mito persistente de que o SRP significa que uma função ou classe deve "fazer apenas uma coisa". Na realidade, Robert C. Martin refinou este conceito em seu livro Clean Architecture para significar que "um módulo deve ser responsável por um, e apenas um, ator" (uma fonte de mudança).

Exemplo prático: Se você tem uma classe RelatorioFinanceiro que calcula os impostos (lógica de negócio para o contador) e também formata o relatório em PDF (lógica de apresentação para o usuário), ela viola o SRP. Se o formato do PDF mudar, a classe muda. Se a regra de imposto mudar, a classe muda. A solução é separar em duas classes: CalculadoraDeImposto e GeradorPdfRelatorio.

O - Open/Closed Principle (Princípio Aberto/Fechado)

De acordo com a documentação da DigitalOcean, este princípio estabelece que entidades de software devem ser abertas para extensão, mas fechadas para modificação. Você deve poder adicionar novos comportamentos sem alterar o código existente, reduzindo a chance de introduzir bugs em sistemas que já funcionam.

Exemplo prático: Em vez de ter uma classe ProcessadorDePagamento com um monte de cláusulas if (tipo == "Cartao") ou if (tipo == "Pix"), você cria uma interface MetodoPagamento. Quando um novo método de pagamento surgir, você cria uma nova classe que implementa a interface, sem tocar no processador principal.

Diagrama de arquitetura de software limpa

L - Liskov Substitution Principle (Princípio da Substituição de Liskov)

Nomeado em homenagem à cientista da computação Barbara Liskov, que o definiu em 1988, este princípio dita que classes derivadas devem poder substituir suas classes base sem quebrar a aplicação.

Exemplo prático: O clássico problema do Retângulo e Quadrado. Se você tem uma classe Retangulo com métodos setLargura e setAltura, e cria uma classe Quadrado herdando dela, você terá problemas. Afinal, mudar a largura de um quadrado obriga a mudar a altura. Substituir um Retângulo por um Quadrado quebraria o comportamento esperado do sistema. A solução é repensar a abstração, talvez usando uma interface comum FormaGeometrica.

I - Interface Segregation Principle (Princípio da Segregação de Interface)

Clientes não devem ser forçados a depender de interfaces ou métodos que não utilizam. É preferível ter várias interfaces específicas do que uma interface única e obesa.

Exemplo prático: Imagine uma interface Trabalhador com os métodos programar() e atenderTelefone(). Um desenvolvedor implementaria programar(), mas seria forçado a ter um método vazio para atenderTelefone(). O correto é segregar em Desenvolvedor e Recepcionista.

D - Dependency Inversion Principle (Princípio da Inversão de Dependência)

Módulos de alto nível não devem depender de módulos de baixo nível; ambos devem depender de abstrações. Como destacado pela LeadDev, este é o princípio por trás do padrão de Injeção de Dependência amplamente usado hoje.

Exemplo prático: Um ServicoDeUsuario (alto nível) não deve instanciar diretamente um MySQLUsuarioRepository (baixo nível). Ele deve depender de uma interface UsuarioRepository. Assim, se você mudar do MySQL para o PostgreSQL, o serviço de usuário permanece inalterado.

Consensos, Controvérsias e o Risco do Overengineering

Hoje, existe um consenso absoluto na indústria de que a aplicação do SOLID melhora a manutenibilidade e, crucialmente, facilita a criação de testes automatizados. O uso do DIP permite a injeção de mocks (objetos simulados) durante os testes unitários, uma prática padrão no mercado.

No entanto, há uma controvérsia em aberto sobre a fragmentação do código. Críticos argumentam que a aplicação rigorosa do SRP e do ISP pode levar a uma proliferação excessiva de classes minúsculas, tornando a navegação no código um pesadelo. Além disso, existe o debate sobre a aplicação desses princípios fora do ecossistema de classes, como em linguagens puramente funcionais.

Desenvolvedor explicando sobre overengineering em uma lousa

Na minha opinião profissional, após mais de duas décadas arquitetando sistemas, afirmo que o SOLID é um conjunto de diretrizes, não de leis divinas. O que diferencia um desenvolvedor júnior, pleno e sênior é justamente a capacidade de ser pragmático. Tentar prever o futuro e criar abstrações para extensões que talvez nunca ocorram (violando o princípio YAGNI - You Aren't Gonna Need It) é um erro clássico. Aplique práticas de Clean Code e SOLID onde a complexidade do negócio exige flexibilidade, mas mantenha a simplicidade em scripts isolados ou provas de conceito.

Perguntas Frequentes

1. O princípio da Responsabilidade Única (SRP) significa que uma função deve fazer apenas uma coisa?

Não. Esse é o mito mais comum sobre o SOLID. Robert C. Martin esclareceu que o SRP significa que um módulo deve ter "apenas um motivo para mudar", ou seja, deve responder a apenas um ator do negócio. Uma classe pode realizar várias operações, desde que todas sirvam ao mesmo propósito e mudem pelas mesmas razões.

2. Inversão de Dependência (DIP) e Injeção de Dependência (DI) são a mesma coisa?

Não. A Inversão de Dependência (DIP) é o princípio de design arquitetural que diz que devemos depender de abstrações e não de implementações concretas. A Injeção de Dependência (DI) é um padrão de projeto e uma técnica prática utilizada para alcançar essa inversão no código.

3. Devo aplicar os princípios SOLID em todos os meus projetos?

Não obrigatoriamente. O SOLID deve ser aplicado de forma pragmática. Em scripts simples, provas de conceito (PoCs) ou projetos de vida curta, a aplicação rigorosa desses princípios pode gerar complexidade desnecessária e atrasos, um fenômeno conhecido como overengineering.

Fontes

Postar um comentário

0 Comentários

Contact form