Executando verificação de segurança...
1

Single Responsibility Principle - Exemplo Estranho

Boa tarde!
Estava lendo este artigo: https://medium.com/@eloufirhatim/solid-principles-in-laravel-1418be178346

"In Laravel, the SRP can be applied by creating smaller, focused classes that handle specific tasks. For example, rather than having a single class that handles user authentication and authorization, it would be better to have separate classes for authentication and authorization."

class User {
  public function register($data) {
    // Register user logic
  }

  public function login($data) {
    // Login logic
  }
}

// Better implementation with SRP
class UserRegistration {
  public function register($data) {
    // Register user logic
  }
}

class UserLogin {
  public function login($data) {
    // Login logic
  }
}

Isso realmente faz sentido? Eu não vejo ganho de simplificadade simplesmente separado duas classes dessa forma

Carregando publicação patrocinada...
2

De repente ai é um exemplo muito simples, mas na minha visão, quando você tem funcionalidades com um código extenso e mais complexas, fica mais fácil uma manutenção futura quando as classes responsáveis por essas atividades estão separadas.

2

O problema desses artigos é que trazem exemplos muito simplórios, que mostram apenas essas classes vazias em vez de mostrar a funcionalidade em um projeto real. Vou tentar explicar neste comentário, mas se não for o suficiente me avisa que faço um artigo ou uma video aula sobre isso.

Se faz sentido ou não, depende do tamanho do projeto e de como o projeto está organizado.

Pode fazer sentido, sim, ter módulos e classes diferentes para funcionalidades diferentes, por mais que os dados utilizados sejam os mesmos. Além disso, pode fazer sentido até ter os dados duplicados no banco de dados, dependendo de como o projeto está organizado.

A ideia de separar as coisas em responsabilidades únicas é evitar que as solicitações de alteração e evolução de uma funcionalidade impacte diretamente outra funcionalidade.

Nesse caso temos as funcionalidades de Registro de usuário e de Login de usuário, que são funcionalidades que imaginamos que sempre andam de mãos dadas. Mas a realidade é que os requisitos de Login podem sofrer alterações que não deveriam impactar diretamente o registro de usuários e vice-versa.

Vamos pegar a classe que mantém tudo junto no mesmo arquivo e pensar na sequência de eventos:

  • Chegou o requisito de que o usuário pode fazer o login com o email e com cpf : aumenta um pouco o código de login. O arquivo fica um pouco maior.
  • Chegou o requisito de que o usuário pode cadastrar vários e-mails pra receber notificações : aumenta o código de registro de usuários E o código de login.
  • Chegou o requisito de que também tem que ter os dados de endereço : aumenta o código de registro, mas não afeta o login.
  • Chegou o requisito de que agora precisa usar 2-factor-authentication : aumenta o código de login e junto com os dados do usuário vão estar os dados do 2-factor-authentication.
  • Bug: os vários e-mails eram apenas para envio de notificação, tem que ter um e-mail principal que é usado pra login : afeta o código existente de registro e de login.

Com o passar do tempo as classes vão ficando enormes e complexas, cada vez mais difícil de dar manutenção e adicionar novas funcionalidades. Isso para projetos que crescem muito e tem muita mudança de requisito

Agora pensando no código em que existe uma classe para cada funcionalidade, ainda vai existir um vínculo entre o login e o usuário, mas as regras serão totalmente separadas.
Vamos ver como fica o tratamento da mesma sequência de requisitos:

  • Chegou o requisito de que o usuário pode fazer o login com o email e com cpf : aumenta apenas o código da classe de login. O de registro de usuário se mantém igual.
  • Chegou o requisito de que o usuário pode cadastrar vários e-mails pra receber notificações : aumenta o código de registro de usuários E surgem as dúvidas: como o código do login é separado, qual e-mail vai ser considerado? É pra considerar todos também? Dependendo da resposta pode ter alteração ou não.
  • Chegou o requisito de que também tem que ter os dados de endereço : aumenta o código de da classe de registro, mas não afeta o login.
  • Chegou o requisito de que agora precisa usar 2-factor-authentication : aumenta o código de login, porém as configurações de login serão armazenadas e validadadas sem afetar o registro de usuário diretamente, podendo ser configurada em outros momentos após o registro de usuários.

A ideia é que as classes sejam pequenas, apenas com as regras que fazem sentido para determinada funcionalidade. Com isso os códigos tendem a ser mais simples, e o crescimento do projeto pode ser feito de forma modularizada e organizada.

Tenha em mente que é uma tentativa, é uma preocupação que você vai ter na hora de desenvolver. Não é garantia de que os bugs vão sumir, e nem de que outros desenvolvedores vão entender com facilidade as decisões que foram tomadas ao longo do tempo.

É necessário sempre manter essa preocupação, e sempre tomar as decisões em conjunto com o time. Desta forma todos vão estar cientes do porquê determinadas funcionalidades estão juntas e outras estão separadas.

Me diz aí se ajudei a entender o conceito, ou se te deixei mais confuso 😂

1

Ta entendi, clarificou um pouco o por que isso seria ideal, é que no artigo ele não apronfudou muito e deixo o exemplo meio aberto demais.

2

Eu vejo o SRP não em relação a classe ter poucas funções, mas uma classe que tem apenas uma motivação para mudar e isso se obtém quando a classe tem "poucas obrigações".

Por exemplo, veja o padrão Active Record, eu acho que esse padrão fere o SRP, pois a classe além de representar uma entidade do negócio como um User, a classe passa ter a responsabilidade de CRUD com o banco de dados.

Outro exemplo, uma classe Pedido quando é responsável por validar os dados, validar os itens, atribuir políticas de descontos, analisar a posição do estoque e etc. Já vi muitos casos do tipo, qualquer coisa que mude no negócio como a regra de descontos, seria motivo de alterar a classe Pedido. Definir esses processos em diferentes classes podem simplificar o processo e a compreensão do todo.

1

Entendi, e seguir o SOLID seria sempre um "Gold Standart" ou depende de cada caso? Por que me parece que cada equipe ou projeto pode ter preferências ou pensamentos diferentes

1

Assim como KISS, DRY e etc, o SOLID te dá uma diretriz de como pensar o seu código da maneira mais legível e manutenível possível. Mas não são regras para serem aplicadas a todo momento, ou até mesmo em todo o projeto.

Na verdade, tem um pessoal que tenta aplicar a todo custo esses princípios em todo lugar que o que alcança é justamente o contrário do objetivo. Por exemplo, o Single Responsibility Principle que você citou no começou, há pessoas que focam tanto na simplicidade das classes que o projeto fica tão fragmentado que acaba se tornando complexo.

Conheça esses conceitos, tente aplicar nos seus projetos, mas saiba que quem manda mesmo é o escopo do projeto use os padrões que se encaixam nessa realidade e não tente mudar a realidade para encaixar nesses padrões.