DEV Community

Cover image for Seja um desenvolvedor melhor com S.O.L.I.D.
Alberto Ventura
Alberto Ventura

Posted on

Seja um desenvolvedor melhor com S.O.L.I.D.

Se você é desenvolvedor há algum tempo ou começou a estudar recentemente, já deve ter notado o termo S.O.L.I.D., tanto nas suas pesquisas quanto nas vagas que aparecem.

Neste post, vou te explicar por que ele é tão importante e por que muitas empresas têm buscado cada vez mais profissionais que entendam e o apliquem.

O que significa SOLID?

O S.O.L.I.D. nada mais é do que um acrônimo de cinco princípios que, quando aplicados, fazem com que seu código atinja outro patamar de qualidade.

Por que ele é importante e é tão requisitado?

O S.O.L.I.D. ajuda o desenvolvedor a escrever códigos mais legíveis, mais flexíveis e escaláveis, permitindo mais robustez e, por consequência, diminuindo a incidência de bugs.

Quais são os princípios?

  • S - Single Responsibility Principle (Princípio da responsabilidade única)
  • O - Open/Closed Principle (Princípio Aberto-Fechado)
  • L - Liskov Substitution Principle (Princípio da substituição de Liskov)
  • I - Interface Segregation Principle (Princípio da Segregação da Interface)
  • D - Dependency Inversion Principle (Princípio da inversão da dependência)
  • Tente interpretar cada um desses princípios como uma abordagem de escrita e implementação, responsável por cada nuance do código.

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

Esse princípio é responsável por definir que cada classe ou função escrita tenha apenas um objetivo, uma única responsabilidade.

Tente pensar assim: “Qual o propósito da sua função/classe? O que ela precisa resolver? Com o que ela precisa lidar?”

Vamos ver um exemplo que viola o princípio da responsabilidade única:

exemplo que viola o princípio da responsabilidade única

Aqui estamos agrupando várias responsabilidades à classe Pagamento:

  • realizar o pagamento
  • gerar relatório
  • enviar email

Como corrigimos esse problema? Simples! Vamos lembrar que cada classe e/ou função tem que ter uma única responsabilidade. No caso da classe Pagamentos, a responsabilidade dela tem que ser apenas com pagamentos (funções também se aplicam). Se temos que gerar relatório ou enviar email, podemos criar uma classe para cada responsabilidade como essas.

Veja o exemplo aplicando o princípio da responsabilidade única:

exemplo aplicando o princípio da responsabilidade única

Percebe como o código fica mais legível, contextualizado e melhor para dar manutenção?

O - Open/Closed Principle

Esse princípio indica que uma função ou classe deve estar sempre aberta para ser estendida, mas fechada para modificação.
Tá, mas o que isso quer dizer?

Pense assim: Algo novo precisa ser inserido no seu código e isso tem que ser estendido sem modificar o código base.

Deixa eu te mostrar um exemplo que viola esse princípio:

exemplo que viola o princípio aberto/fechado

Veja o código acima. Imagine que agora você precisa implementar pagamentos via Pix e, para obedecer à estrutura, você vai precisar modificar o código, dando brecha para bugs.

Agora deixa eu te mostrar o mesmo código, só que aplicando o princípio de aberto/fechado:

exemplo aplicando o princípio aberto/fechado

Percebe como dessa forma você torna seu código escalável, fácil de ler e estender? Agora você pode acrescentar quantas situações precisar, sem modificar o código principal!

Dica: as interfaces são suas amigas; você sempre pode contar com elas!

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

O princípio da substituição de Liskov define que uma subclasse sempre poderá ser substituída por sua superclasse, pois a subclasse deve ter o comportamento igual ao da sua superclasse.

Calma lá, o que é superclasse?

Deixa eu te lembrar: Pense na superclasse como a classe (classe pai) que é herdada por subclasses (classes filhas). Por exemplo, uma superclasse do tipo Felino será herdada pela subclasse do tipo Gato.

E como esse princípio seria aplicado na prática?

Primeiro, deixa eu te mostrar um exemplo que viola o Princípio da Substituição de Liskov:

exemplo que viola o princípio da substituição de Liskov

Se a gente reparar, tem algo estranho no código, pois, caso a gente tente executar o método voar, nesse contexto vai dar errado, porque, apesar de um pinguim ser uma ave, ele não voa.

E como a gente resolve isso? Simples! Vamos criar derivações da classe pai para o contexto que precisamos, por exemplo:

exemplo aplicando o princípio da substituição de Liskov

Percebe como a gente acaba modelando nosso código de modo mais bem estruturado? Desse modo, a gente evita erros surpresa e simplifica a manutenção do código.

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

Esse princípio define que uma classe não deve implementar interfaces genéricas ou métodos que não irá utilizar.

Vamos ver um exemplo que viola esse princípio:

exemplo que viola o princípio da segregação de interface

Se implementarmos a interface Funcionário do jeito que ela está, vamos violar o princípio da Segregação de Interface. Apesar de todos receberem salário, um atendente gerencia projeto? Um gerente realiza atendimento? Estaremos implementando métodos que as classes não irão usar, e isso é ruim para a coesão e flexibilidade do nosso sistema.

Como podemos solucionar? Simples, vamos segregar! Veja o exemplo abaixo aplicando o princípio da Segregação de Interface:

exemplo aplicando o princípio da segregação de interface

Ao invés de termos apenas uma interface Funcionário, criamos outras que recebem os métodos de forma separada. Percebe que dessa forma a gente consegue segregar as implementações?

Se no futuro for necessário adicionar outra função que só o gerente faz (como aprovarOrçamento), podemos adicionar mais interfaces sem alterar as classes que não precisam dessa função.

Dica: quando for implementar uma interface, pense: essa classe irá usar tudo dessa interface? Não? Então vamos segregar!

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

Esse princípio define que todas as classes devem depender de abstrações (interfaces) e não de outras classes.

Esse princípio nos orienta que, caso precisemos fazer acoplamentos e integrações, a porta de entrada deve ser através de interfaces, e não de instâncias internas.

Vamos ver um exemplo que viola esse princípio:

exemplo que viola o princípio da inversão de dependência

Dessa forma, sua classe está dependendo de um mau acoplamento, pois se você mudar algo na sua dependência, vai precisar alterar a classe (lembra do princípio de Aberto/Fechado?).

Por exemplo, se precisarmos inserir outro meio de pagamento, vamos precisar mexer no código, porque o serviço de pagamento está totalmente dependente da classe CartãoDeCrédito.

A melhor forma de resolver esse problema é tornando sua classe independente, através do uso de interfaces!

Vamos modificar o código anterior para que obedeça ao princípio da inversão de dependências:

exemplo aplicando o princípio da inversão de dependência

Percebe que dessa forma a gente faz um desacoplamento das dependências e torna sua classe independente? A classe não precisa saber ou instanciar o que vai usar; tudo o que ela precisa saber está na interface!

Se você precisar implementar outros meios de pagamento, sua interface cuida para que o serviço de pagamentos entenda e você não precise alterar nada nele.

Desse modo, você torna suas classes mais robustas, extensíveis e flexíveis, ajudando na qualidade e manutenção!

Dica: sempre que precisar instanciar ou inserir algo na classe, se pergunte: eu posso fazer isso através de uma interface?

Pense em interfaces como um contrato, um contrato que garante que o que você está usando vai receber o que você espera!

--

Agora você sabe o que é o S.O.L.I.D., o que significa cada princípio e como ele se aplica no código. Aproveite agora para praticar, aplicando os 5 princípios com essas perguntinhas básicas:

  • S: Qual o propósito dessa classe ou função? O que ela precisa resolver?
  • O: O que eu preciso acrescentar vai modificar a classe? Será que eu não posso apenas estender?
  • L: Essa subclasse que eu estou implementando pode ser substituída pela sua superclasse?
  • I: Essa classe vai implementar tudo o que sua interface disponibiliza?
  • D: Como posso tornar essa classe o mais independente possível? Posso fazer isso através de uma interface?

Por enquanto é isso! Espero ter ajudado!
Gostaria de contribuir com algo? Coloque nos comentários, bora estender!

Top comments (0)