SOLID é um acrônimo que representa cinco princípios no design de softwares orientados a objetos, sendo:
Single Responsability
Open-Closed
Liskov Substitution
Interface Segregation
Dependency Inversion Principle
Embora Go não seja uma linguagem orientada a objetos, ainda assim conseguimos utilizar os princípios de SOLID. Abaixo, vamos ver com mais detalhes cada um dos princípios.
Single Responsability
Uma classe ou, como é no caso do Go, uma struct deve ter uma única responsabilidade. Ou seja, cada struct deve ser projetada para executar uma determinada ação.
Pensando em um CRUD, é claro que você não terá uma struct para cada uma das ações (Create, Read, Update e Delete). Mas também não terá somente uma struct para lidar com todas as responsabilidades do package.
O ideal é ter pelo menos uma struct que represente a entidade do package. Uma para lidar com as transações com banco de dados, comumente chamada de repository. E outra para tratar as requests, independente se forem via API ou em algum modelo MVC.
Open-Closed
Uma classe deve estar aberta para extensões, mas fechada para modificações. Ou seja, sempre que for necessário adicionar funcionalidades, devemos estender a classe ao invés de modificá-la.
Embora seja possível através da estratégia de embedding, esse princípio é um pouco mais difícil de ser aplicado em Go.
Isso por que, diferente de uma linguagem que implementa orientação a objetos, em Go, nem tudo estará atrelado a uma struct.
Mesmo assim, para um maior reaproveitamento das funções do sistema, é importante que elas tenham suas responsabilidades muito bem definidas.
Liskov Substitution
Classes “filhas” podem ser utilizadas no lugar das classes “pais” sem que o programa quebre.
Esse é outro princípio que, para ser aplicado ao Go, talvez exija algumas mudanças que em outras linguagens, como, por exemplo, o PHP, não é necessário.
Como Go é uma linguagem fortemente tipada, não é possível passar struct do tipo Bar
, onde só é aceito structs do tipo Foo
.
Outro ponto que vale lembra é que, em Go, não existe o conceito de herança. Logo, mesmo que uma struct utilize-se da estratégia de embedding, ela não tem relação direta com a outra struct como acontece na herança de classe.
Interface Segregation
Uma classe não deve ser obrigada a implementar interfaces e métodos que não utilizará. Em outras palavras, é melhor ter 6 interfaces bem específicas, do que 2 mais genéricas.
Esse princípio, inclusive, é amplamente aplicado no core da linguagem Go. Se olharmos para o package io
, temos, por exemplo, as interfaces:
- io.Reader
- io.Writer
- io.ReadWriter
Onde a terceira nada mais é do que um embedding das duas primeiras.
Dependency Inversion Principle
Dependências devem ser abstraídas, para que os módulos de alto nível não dependam dos módulos de baixo nível.
Uma forma de implementar esse conceito, é utilizar interfaces para definir atributos de structs e parâmetros de funções. Assim, ao invés de esperar um tipo concreto, ou seja, altamente acoplado, esperamos qualquer tipo que implemente a interface.
Conclusão
Embora não seja possível aplicar todos os conceitos de SOLID em Go da mesma forma que em linguagens orientadas a objetos, ainda assim podemos construir softwares altamente escaláveis e robustos.
No meu ponto de vista, os conceitos que não conseguimos aplicar parcial ou integralmente, não trazem impacto nos quesitos robustez, escalabilidade e flexibilidade do software.
Em um próximo post, vou trazer exemplo de código escrito em Go para cobrir cada um dos pontos aqui explicados.
Por isso, se você ainda não é assinante, não deixe de assinar nossa newsletter. É gratuita e seus dados não serão vendidos para anunciantes 😉.
Até a próxima!
[…] você não viu o primeiro post da série, recomendo a leitura para ter uma visão geral do que é […]
[…] O que é SOLID? […]
[…] O que é SOLID? […]
[…] O que é SOLID? […]
[…] O que é SOLID? […]