S.O.L.I.D. – Princípios Fundamentais para Aplicações de Alto Nível

Este artigo aborda os cinco princípios do S.O.L.I.D. que é um acrônimo altamente recomendado para programadores que buscam desenvolver aplicações em OOP que sejam robustas, escaláveis e flexíveis.

No início do presente século o cientista da computação Michael Feathers criou o acrônimo S.O.L.I.D. baseando-se na abordagem de Robert C. Martin acerca de arquitetura e desenvolvimento de software. Basicamente, essa importante “sopa de letrinhas” tornou-se fundamental para a engenharia de aplicações profissionais por representarem cinco princípios que deixam o código muito mais legível, organizado, desacoplado e refatorável, viabilizando – com isso – sua evolução e manutenibilidade. Vamos, portanto, verificar a seguir o significado de cada uma das letras dentro do contexto das melhores práticas para aqueles que desenvolvem aplicações em linguagens que suportam programação orientada a objetos, do inglês “Object Oriented Programming(OPP).

S – “Single Responsability Principle” (Princípio da Responsabilidade Única)

Este é um dos mais importantes dentre os cinco princípios, e diz que uma classe ou método deve ter responsabilidade específica, ou seja, uma única tarefa ou ação a executar. Isso pode garantir que diante da necessidade de se fazer ampliações nessas entidades estaremos praticamente isentos de injetarmos pequenos “bugs” de forma inconsciente, o que poderia ser diferente ao modificarmos uma ”god class”, que são classes que fazem de tudo, onde a tarefa de se alterar uma funcionalidade sem afetar as demais pode ser extremamente árdua. Observe abaixo que a classe “DebitoContaCorrente” viola o princípio da responsabilidade única quando acumula um método para validar saldo, outro para debitar na conta e um último para emitir comprovante. Como conseqüência teremos um alto acoplamento, baixa coesão, dificuldade de ampliação da classe e impossibilidade de implementação de testes automatizados.

Uma forma adequada de se escrever um código com as mesmas funcionalidades, acatando o princípio “SRP”, é mostrada a seguir. Veja que agora temos três classes e cada uma delas respeita uma especificidade.

O – “Open-Close Principle” (Princípio Aberto-Fechado)

Este segundo princípio requer que os objetos ou entidades estejam abertos para ampliações e fechados para modificações. Em outras palavras, significa afirmar que uma entidade deve ser concebida de forma a permitir o incremento de novos recursos ou comportamentos sem a necessidade de alteração do código original. No exemplo a seguir temos uma classe para calcular o desconto que cada operadora concederá aos clientes na fatura mensal do cartão de crédito. Repare que essa classe não obedece ao princípio do “OCP”, pois se precisarmos incluir mais operadoras teremos que alterar a rotina incrementado proporcionalmente outras estruturas condicionais; com isso, estaríamos expostos ao risco da incerteza de injetarmos eventuais “bugs” em um algoritmo que anteriormente estava funcionando.

Vimos que é extremamente relevante considerarmos a teoria de “Uncle Bob” desde o princípio da elaboração do nosso código de forma a construirmos nossas classes utilizando abstrações; dessa maneira, não serão necessárias alterações do conteúdo já existente para incremento de novas variações, tão somente faremos a ampliação de métodos na classe. A seguir temos um exemplo de como poderia ser essa prática.

L – “Liskov Substitute Principle” (Princípio da Substituição de Liskov)

Este princípio foi introduzido no final da década de 80 por uma cientista da computação chamada Barbara Liskov. Sua afirmação é de que uma classe derivada deve necessariamente poder ser substituída por sua classe base, sem que seja necessário alterar o código. Um exemplo clássico que pode ser citado para ilustrar este princípio seria a criação de uma sub-classe que calcula a área de um quadrado, sendo que essa tem como base uma classe que calcula a área de um retângulo. Embora ambos sejam quadriláteros geométricos o quadrado tem a particularidade de que seus lados precisam ser iguais; logo, o cálculo da área implementado na classe base (Retângulo) não poderia ser utilizado da forma como foi concebido, sendo necessário sobrescrevê-lo na classe filha (Quadrado) para acrescentar uma exceção caso os valores dos parâmetros referentes ao lado sejam diferentes. Uma possível solução seria a escrita de uma classe base que atendesse ao cálculo dos dois quadriláteros, ou seja, uma classe que poderia se chamar quadrilátero e simplesmente calcularia a área retornando o produto de: base * altura; sendo assim, outras duas classes derivadas dessa implementariam suas respectivas particularidades sem a necessidade de sobrescrever a classe base. Para ilustrar melhor essa possibilidade, observe o código a seguir.

I – “Interface Segregation Principle” (Princípio da Segregação de Interface)

O quarto princípio preconiza que é melhor termos várias interfaces especificas do que  uma interface genérica. No exemplo hipotético abaixo temos a interface “ICompra” sendo implementada pelas classes “CompraPresencial” e “CompraOnLine”. Este código viola o princípio de “ISP” devido ao fato de que a classe “CompraPresencial” não implementa o método “PagarComCartao”, visto que ela não precisa desse método; dessa forma, a referida classe viola o “ISP” ao implementar um método que não utiliza.

Uma opção adequada para corrigirmos isso seria criarmos mais interfaces a fim de evitarmos a implementação de métodos desnecessários dentro das demais classes. Como está representado no exemplo abaixo.

D – “Dependence Invertion Principle” (Princípio da Inversão de Dependências)

E poor último, mas não menos importante, temos o princípio da inversão de dependência. Este princípio tem o objetivo de reduzir o acoplamento entre as classes fazendo com que os módulos de alto nível não dependam de módulos de baixo nível, mas que ambos dependam de abstrações. Também, que as abstrações não dependam dos detalhes, e sim os detalhes dependam das abstrações. No exemplo abaixo ambas as classes – “PushButton” e “Led” – são classes concretas; portanto, a classe “PushButton” está fortemente acoplada à classe “Led”. Devido a isso, qualquer mudança ocorrida na classe “Led”, por mais simples que seja, fará com que “PushButton” pare de funcionar.

Para atender este último princípio, devemos fazer de forma que a implementação dependa da abstração. Na prática, vamos inverter a dependência de “PushButton” para a classe “Led” fazendo com que ambas passem a depender de uma abstração, que no exemplo abaixo é representada pela interface “Dispositivo”.

Conclusão

Como foi exposto neste artigo, o S.O.L.I.D. é um conjunto de princípios fundamentais em arquiteturas de softwares profissionais, pois eles tem a capacidade de fazer com que as aplicações fiquem muito mais robustas, escaláveis e flexíveis, de forma a proporcionar enorme facilidade à refatorações e às ampliações. Além disso, existem também outras excelentes práticas de programação, tais como: “Clean Code”, “Designer Parttners” e “Padrões de Arquiteturas de Software”, que reforçam a escrita de códigos consistentes por isso são regularmente praticados pelos “Seniors Devops Engineers”. Mas esses assuntos serão tópicos para futuras abordagens.

Saiba mais

Webinar Gravado: Arquitetura de Software para Sistemas Embarcados

Webinar Gravado: Metodologias de Desenvolvimento de Software Embarcado

Aplicação de usabilidade em desenvolvimento de software

Graduado em Engenharia Elétrica com ênfase em eletrônica e Pós-Graduado em Desenvolvimento de Sistemas Embarcados, possui experiência em rotinas de gerenciamento de atividades operacionais, vivência em nacionalização e atualização tecnológica de máquinas e equipamentos automáticos, bem como automação de processos, desenvolvimento de sistemas embarcados e dispositivo IoT para aplicação nos setores de mineração, indústria, saúde e outros.

Notificações
Notificar
guest
0 Comentários
Inline Feedbacks
View all comments

WEBINAR

Imagens de Ultrassom: Princípios e Aplicações

DATA: 26/10 ÀS 19:30 H