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

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

Eae pessoal, tudo bem?

Vou começar a postar os principios S.O.L.I.D. por ser algo que me ajudou MUITO na qualidade de codigo (sei que o tema está meio batido com o tanto de videos, artigos e etc). Mas o real motivo de começar é de aprender e me acostumar a estruturar textos de maneira legivel e que faça sentido (o que nunca fui muito bom), então se quiserem dar dicas ou fazer criticas sobre a estrutura, gramática e/ou conhecimento técnico sintam-se a vontade.

Single Responsability Principle (SRP)

O que isso significa?

Históricamente ele é descrito com essa "simples" e pequena fraze:

Um módulo deve ter um, e apenas um, motivo para mudar.

Porém os sistemas de softwares são mudados para satisfazer um "user" ou um "stakeholder". Fazendo com que a fraze fique um pouco diferente:

Um módulo deve ter um, e apenas um, user ou stakeholder.

Mas como é muito provavel que a tenha mais de um user ou stakeholder querendo essa mudança, então devemos nos referir ao grupo de users e ou stakeholders podendo ser um ator (sim aquele mesmo do UML). Sendo assim:

Um módulo deve ter um, e apenas um, ator.

"A maneira mais simples de descrevelo é um arquivo de código-fonte." ~ Robert C. Martin
em "Clean Architecture: A Craftsman's Guide to Software Structure and Design"

Ainda assim acredito estar meio confuso, por exemplo:

  • Cada arquivo deve ser responsável por fazer apenas uma coisa.

  • Cada função/classe desse arquivo deve também ter apenas uma responsabilidade, tornando-a um expecialista no que ela foi prosta a fazer.

Tem como identificar?

Os dois principais sintomas que Robert C. Martin fala são:

Duplicação acidental

class Employee {
  calculatePay() {
    //calcula o pagamento
  };
  reportHours() {
    //gera relatorio das horas
  }
  save() {
    // salva as alterações na base de dados
  }
}

Essa classe é um bom exemplo para visualizar a duplicação do SRP por conta de:

  • calculatePay() é um método específico de um ator da área de finanças
  • reportHours() é um método específico de um ator da área de recursos humanos
  • save() é um método específico de um ator da área de tecnologia

O acoplamento destes três métodos faz com que os 3 atores diferentes acabem se tornando apenas "um employee" fazendo com que todos tenham as peculiaridades de todos, ocorrendo uma duplicação acidental.

Um outro exemplo de como isso é maléfico

Imagine que tem um método regularHours() que é utilizado no calculatePay() e no reportHours()

De maneira um pouco mais visual
calculatePay() -> regularHours() <- reportHours()

Porem o ator de finanças quer que regularHours() tenha algumas alterações para atender as necessidades dele

Mas isso afetaria o reportHours(), onde o ator de recursos humanos que já avisou que não pode ocorrer essas mudanças, pois irá gerar o relatório com informações inválidas.

Obs: nesse caso ambos os atores estão cientes das alterações e de seus impactos quanto maior e mais complexo é o sistema, mais dificil de ter noção e prever o que pode acontecer, podendo gerar bugs, informações invalidas, atrapalhar nas tomadas de decisões, falhas de segurança e por ai vai.

Merges

Não é muito dificil de imaginar que merges vão ser comum de ocorrer em sistemas onde arquivos possuem multiplas funcionalidades.

Voltando ao exemplo do Employee

Imagine que o ator da área de tecnologia ele precise fazer uma alteração no schema de employee na base de dados e por coincidencia o ator de recursos humanos também decide alterar o employee para mudar o formato de data/hora.

Quando eles tentam subir suas as alterações causa um conflito, obviamente isso não é o fim do mundo, porem tras um risco para o sistema, já que irá ter conflitos mais frequentemente, aumenta a possibilidade de quem estiver resolvendo o conflito errar em algo.

O que eu ganho resolvendo isso?

  • Facilita a implementação de uma classe, bem como o seu entendimento e manutenção.
  • Facilita a alocação de um único responsável por manter uma classe.
  • Facilita o reúso e teste de uma classe, pois é mais simples reusar e testar uma classe coesa do que uma classe com várias responsabilidades.

Como resolvo isso?

Uma das maneiras de solucionar é separando as responsabilidades em cada arquivo

Continuando o problema do employee

Separando tudo podemos concluir que temos duas camadas

  • Dados (os dados do employee)
  • Serviço (as funcionalidades dele que cada ator precisa)

Poderiamos ter:

EmployeeData.ts
Para a representação dos empregados

interface EmployeeData {
 // ... estrutura de dados do employee
}

PayCalculator.ts

class PayCalculator {
 execute(employee:EmployeeData): Promise<number>{
   // ... implementação do calculo de pagamento
 }
}

HourReporter.ts

class HourReporter {
 execute(employee:EmployeeData): Promise<HourReport>{
   // ... implementação do relatório de horas
 }
}

EmployeeSaver.ts

class HourReporter {
 execute(employee:EmployeeData): Promise<void>{
   // ... Salva as alterações do employee
 }
}

e para representar cada ator poderiamos usar o Facade pattern

EmployeeFacade.ts

class EmployeeFacade {
    private employee: EmployeeData
}

e herdando do EmployeeFacade poderiamos adicionar os metodos de cada ator para dentro dele, deixando o "módulo" de employee com maior facilidade de manutenção, leitura.

Conclusão

Basicamente o Princípio de responsábilidade única é sobre funções e classes, limitando seu escopo de uma unica funcionalidade por arquivo a nivel de componentes.
Mas pelo lado arquitetural ele define os limites do contexto.

Fontes

Carregando publicação patrocinada...
1

O que eu não gosto nesse tipo de livro ainda mais desse autor é o jeito de escrever!
Em computação em geral nada ta certo ou nada ta realmente errado.

O jeito que ele escreve faz o leitor pensar que se não fizer exatamente o que é dito como lei, esta errando! Ou seja quem não fizer mas conhece as "regras" se sente errando, estando fora do que é o "certo"..

Um bom livro que não faz isso é o livro sobre DDD.
O autor é bem claro que nem sempre o que tem lá é a melhor ou unica opção.
Que ele da dicas que podem ou não ajudar em determinados problemas!