Princípios SOLID: o princípio da Responsabilidade Única

Por Felipe Barbosa, 25/04/2023

Clean Architecture

Na parte III do Clean Architecture, somos apresentados aos famosos princípios SOLID. Esses princípios foram formalmente apresentados pela primeira vez no livro Agile Software Development, Principles, Patterns and Practice em 2002 e são trazidos aqui novamente no contexto mais amplo da arquitetura.

Arquitetura: uma discussão de múltiplos níveis

É interessante notar como o livro constrói uma progressão no nível hierárquico das entidades e elementos alvo da discussão sobre arquitetura.

No nível mais baixo, está o "clean code" ou as boas práticas de programação. Coisas como escrever funções com uma única funcionalidade e com menos parâmetros, saber nomear variáveis, refatorar código difícil de entender em uma estrutura clara. Isso é mencionado, mas não discutido neste livro, porque existe um outro de mesmo nome inteiramente dedicado ao assunto, o Clean Code.

O livro segue com uma discussão dos paradigmas de programação e sua importância para arquitetura e, em seguida, somo apresentados aos princípios de design de "classes". A palavra "classe" aqui se refere a um agrupamento de dados e funcionalidades relativas a esses dados - e não necessariamente às "classes" de linguagens orientadas a objetos. Portanto, esse princípios são aplicáveis de forma ampla e não pressupõe o uso OO. Poderia-se usar o termo componente, porém o autor reserva esse termo para entidades de nível hierárquico maior, como veremos mais adiante.

O que são e qual o objetivo dos princípios SOLID

Os princípios SOLID são uma série de práticas que têm o intuito de melhorar a estrutura, confiabilidade, testabilidade e facilidade de manutenção do código que escrevemos.

Especificamente, o objetivo desses princípios é o de combater 7 tipos possíveis de falhas identificadas pelo autor. Os três defeitos ou falhas principais que nos interessam de perto são explicados abaixo e os demais são apenas mencionados em seguida.

  1. Rigidez - é a dificuldade fazer mudanças no código, porque uma alteração em uma parte do sistema nos força a fazer mudanças em várias outras partes;

  2. Fragilidade - é quando mudanças em uma parte do programa fazem o sistema quebrar em partes que, conceitualmente, não têm nada a ver a parte que foi alterada;

  3. Imobilidade - é a dificuldade extrair componentes reutilizáveis do sistemas porque esses componentes estão fortemente acoplados.

Os demais são

  1. Viscosidade;
  2. Complexidade desnecessária;
  3. Repetição desnecessária;
  4. Opacidade.

Com essas falhas de design em mente, vamos ver de que forma esses princípios nos ajudam a combatê-las.

Antes de tudo, é bom enfatizar que o nome dos princípios e a sua definição são apenas uma forma de nos remeter ao que eles se referem. Para entendê-los precisamos investigá-los a fundo.

O princípio da Responsabilidade Única

O primeiro princípio é o princípio da responsabilidade única e ele que diz que

Uma entidade deve ter um único motivo para ser alterada

Ou, alternativamente:

Uma entidade deve ter um único eixo de mudança

Primeiro vamos raciocinar de uma maneira abstrata e em seguida vamos analisar dois exemplos.

Se uma classe tem mais de uma responsabilidade, essas responsabilidades se tornam acopladas. Isso significa que, se precisarmos fazer mudanças em uma das atribuições desta classe, essa mudança pode impactar as outras responsabilidades/atribuições. Confuso? Vamos ver como isso acontece na prática.

Exemplo 1: Apresentação vs. Lógica

Dê uma olhada nesse diagrama. Ele representa um programa em que a classe Retângulo é usada tanto por um módulo de geometria computacional, quanto por um módulo gráfico. Essa dependência é representada pelas setas que saem das caixas, que, por sua vez, representam os respectivos componentes.

Observe que nossa classe Retângulo tem a dupla responsabilidade de fazer os cálculos geométricos (utilizada pelo módulo de geometria computacional) e de desenhar-se (utilizada pelo módulo gráfico).

Isso tem consequências bastante negativas para o projeto. Em primeiro lugar, perceba que, nesse modelo, o módulo de geometria computacional passa a ter uma dependência no módulo gráfico, apesar de ele jamais precisar renderizar um retângulo.

Além disso, se mudanças nos requerimentos do módulo gráfico necessitarem de alterações da classe Retângulo, essas mudanças podem impactar a o módulo de geometria computacional. E assim, no mínimo, nós precisaríamos compilar novamente (no caso de linguagens compiladas, claro) e testar novamente um módulo não relacionado com nossa mudança.

Fica claro que esse acoplamento de responsabilidade é bastante nocivo para a nossa aplicação.

Observe agora este design alternativo.

Com esse modelo, mudanças feitas na renderização do retângulo jamais podem afetar nosso módulo de geometria computacional.

Exemplo 2: Persistência vs. Regras de Negócio

Um exemplo mais realista e bastante corriqueiro é o do acoplamento de regras de negócio com a camada de persistência da aplicação.

Nesse diagrama, a classe Employee tem a dupla responsabilidade de guardar as regras de negócio e de persistir os dados na camada de persistência. Dessa forma, a classe depende diretamente da camada de persistência. Isso significa que mudanças nesse componente podem afetar diretamente as regras de negócio, o que é absurdo.

Novamente, um modelo melhor para essa situação é o que consta no diagrama abaixo.

Aqui separamos completamente as responsabilidades de guardar as regras de negócio e de persistência utilizando inversão de dependência.

A interconexão dos princípios

Como veremos em seguida, os princípios SOLID são altamente dependentes um dos outros. Você acabou de testemunhar como usamos inversão de dependência para separar responsabilidades. Isso acontece com frequência é um aspecto bastante positivo, porque boas práticas vão puxando boas práticas.

E acontece que o recíproca frequentemente é verdadeira: os maus padrões e as más práticas nos levam para um buraco negro do qual é bastante difícil sair. Essa é uma das falhas de design que foram mencionadas e que fica explicada aqui: trata-se da viscosidade, que é quando se tem um projeto em que é mais fácil fazer a coisa "errada" do que a coisa "certa".

E por hoje é só. Na próxima publicação, discutiremos um dos mais importantes princípios: o princípio aberto-fechado.

Vejo vocês lá, cheers!

Este artigo é parte da série Clean Architecture baseada no livro de mesmo nome do Uncle Bob. Confira os demais:

Seguinte: Hold on tight 🥰

Anterior: Paradigmas de programação e Arquitetura

Gostando até aqui? ✍️

Receba atualizações de conteúdo diretamente na sua caixa de entrada!