Desenvolvimento

14 mar, 2019

S.O.L.I.D no dia a dia – Como ter um código limpo

684 visualizações
Publicidade

Uma das maiores dificuldades no desenvolvimento de software é olhar para o código desenvolvido e dizer: “Essa solução foi uma das melhores, meu código está muito bom”. Qual motivo faz com que desenvolvedores tenham essa sensação?

Não conseguimos responder essa questão com facilidade, mas esse assunto é diretamente ligado aos princípios do SOLID que podem ajudar a enxergar melhor o desenvolvimento e aprimorar a codificação.

O que é SOLID?

SOLID é um acrônimo dos cinco primeiros princípios da programação orientada a objetos e sua divisão consiste em:

  • [S]ingle Responsability Principle (Princípio da Responsabilidade Única);
  • [O]pen/Closed Principle (Princípio do Aberto/Fechado);
  • [L]iskov Substitution Principle (Princípio da Substituição de Liskov);
  • [I]nterface Segregation Principle (Princípio da Segregação de Interfaces);
  • [D]ependency Inversion Principle (Princípio da Inversão de Dependências).

O objetivo deste artigo é mostrar como esses princípios podem ser aplicados no dia a dia no desenvolvimento de software.

O dia a dia de pessoas desenvolvedoras

O principal objetivo do desenvolvimento de sistemas é a entrega de valor, mas esses valores são vistos de diferentes perspectivas, e aqui vamos abordar a perspectiva do time de desenvolvimento.

Para o time de desenvolvimento, entregar valor consiste em ter um código bem escrito e o produto funcionando como o cliente contratou.

Porém, é difícil determinar o que significa ter esse código bem escrito, então para isso existem técnicas e padrões de projeto para auxiliar no desenvolvimento de sistemas, e o SOLID encaixa perfeitamente para a escrita de um código mais limpo: o seu entendimento é bem simples e a aplicabilidade é bem fácil.

Aplicando os cinco princípios com uma linguagem simples

Imagine que neste momento estamos desenvolvendo uma funcionalidade nova como, por exemplo, um fluxo de pagamento, e esse fluxo possui dois tipos de pagamento: boleto e cartão de crédito.

No início do desenvolvimento criamos uma única classe, e percebemos que no decorrer as regras de boletos são diferentes das regras do cartão de crédito e que estão todas na mesma classe.

Aqui aplica-se o SRP (Single Responsability Principle), onde separamos as regras de boleto das regras de cartão de crédito – cada uma em sua respectiva classe, e possuímos um contrato, uma interface chamada, por exemplo, PaymentMethod. Nesse exemplo parece simples, mas sabemos que um fluxo de pagamento é muito mais complexo e que o difícil é definir o que é responsabilidade.

Agora, e se nosso fluxo de pagamento possuir descontos para que paga a fatura antes do prazo, até 10 dias antes, 10% de desconto, após 10 dias e até 5 dias antes, 5% de desconto (isso para compra de boleto e para cartão de crédito).

Para pagamento à vista temos 15% de desconto, para pagamento em até três vezes, 10% de desconto, e assim o sistema vai ficando cheio de regras, vai se tornando complexo e começam alguns questionamentos por parte do desenvolvimento como, por exemplo: “Qual a melhor forma de desenvolvimento para futuras manutenções?”.

Se analisarmos o caso anterior podemos visualizar uma grande quantidade de ifs para solucionar o problema e, com isso, vamos acoplando cada vez mais o código, então aqui temos o princípio OCP (Open/Closed Principle) aberto para extensão e fechado para alteração.

Neste momento utilizaremos abstração, como utilizar a abstração para tornar nosso código mais robusto. No caso do nosso exemplo poderíamos criar uma abstração paymentMethod que será um contrato para os meios de pagamentos serem implementados.

Esse contrato já faz parte do princípio LSP (Liskov Substitution Principle), que significa garantir que as classes derivadas sejam usadas transparentemente. Onde se vê uma classe base, todo código que depende da classe base será capaz de usar, em tempo de execução.

Então chegamos ao princípio ISP (Interface Segregation Principle). Ao utilizar abstração é muito comum que as interfaces fiquem com mais responsabilidades do que deveriam. Esse princípio nos diz que é sempre melhor termos interfaces magras com responsabilidade única.

Como observamos, para o desenvolvimento da funcionalidade anterior nos leva a abstração e o último princípio: DIP (Dependency Inversion Principle). Antes de falarmos deste, uma pergunta:

  • É possível eliminar o acoplamento?

Não é possível. Como sabemos, em sistemas de médio e grande porte, uma classe sempre dependerá de outra. Portanto, o importante é diferenciar o acoplamento sempre, por isso, esse princípio nos mostra que um classe deve depender sempre de um módulo mais estável que ela. No nosso exemplo, PaymentMethod deve ser mais estável, com poucas mudanças, pois outras classes dependerão dela.

O artigo demonstra de uma maneira simples a importância de princípios para desenvolvimento de software. Claro que no dia a dia o trabalho que desenvolvemos é mais complexo, porém, devemos começar a pensar mais abstrato e ir aplicando o que aprendemos em vários módulos, não de uma única vez, mas aos poucos. Assim, será possível notar a evolução na escrita do código.