Eu não acho útil hoje em dia debater sobre o que constitui ou não uma única responsabilidade ou uma única razão para mudar. Eu proporia um princípio do luto mínimo em seu lugar:
Minimum Grief Principle: code should either seek to minimize its probability of requiring changes or maximize the ease of being changed.
Como é isso? Não deve levar um cientista de foguetes para descobrir por que isso pode ajudar a reduzir os custos de manutenção e, esperamos, não deve ser um ponto de debate interminável, mas, como acontece com o SOLID em geral, não é algo que se aplique cegamente em todos os lugares. É algo a considerar ao equilibrar trade-offs.
Quanto à probabilidade de exigir mudanças, isso fica abaixo de:
- Bom teste (maior confiabilidade).
- Envolvendo apenas o código mínimo necessário para fazer algo específico (isso pode incluir a redução de acoplamentos aferentes).
- Apenas tornando o código foda no que ele faz (veja Princípio Make Badass).
Quanto à dificuldade de fazer mudanças, aumenta com acoplamentos eferentes. O teste introduz acoplamentos eferentes, mas melhora a confiabilidade. Bem feito, geralmente faz mais bem do que mal e é totalmente aceitável e promovido pelo Princípio Mínimo do Sofrimento.
Make Badass Principle: classes that are used in many places should be awesome. They should be reliable, efficient if that ties to their quality, etc.
E o Princípio do Make Badass está ligado ao Princípio do Sofrimento Mínimo, uma vez que as coisas ruins encontrarão uma probabilidade menor de exigir mudanças do que as que sugam o que fazem.
I would have started by pointing to the paradox mentioned above, and
then indicate that the SRP is highly dependent on the level of
granularity you want to consider and that if you take it far enough,
any class containing more than one property or one method violates it.
Do ponto de vista do SRP, uma classe que mal faz qualquer coisa certamente teria apenas um (às vezes zero) motivos para mudar:
class Float
{
public:
explicit Float(float val);
float get() const;
void set(float new_val);
};
Isso praticamente não tem motivos para mudar! É melhor que o SRP. É ZRP!
A não ser que eu sugira que esteja em flagrante violação do Princípio Make Badass. Também é absolutamente inútil. Algo que faz tão pouco não pode esperar ser durão. Tem pouca informação (TLI). E naturalmente quando você tem algo que é TLI, ele não pode fazer nada realmente significativo, nem mesmo com a informação que ele encapsula, então ele tem que vazar para o mundo externo na esperança de que alguém realmente faça algo significativo e foda. E esse vazamento é bom para algo que é apenas para agregar dados e nada mais, mas esse limite é a diferença como eu vejo entre "dados" e "objetos".
É claro que algo que é TMI também é ruim. Podemos colocar todo o nosso software em uma classe. Pode até ter apenas um método run
. E alguém pode até argumentar que agora tem uma razão muito ampla para mudar: "Essa classe só precisará ser alterada se o software precisar de melhorias". Eu estou sendo bobo, mas é claro que podemos imaginar todos os problemas de manutenção com isso.
Portanto, há um equilíbrio entre a granularidade ou a grossura dos objetos que você projeta. Eu sempre julgo isso pela quantidade de informação que você tem que vazar para o mundo externo e quanta funcionalidade significativa ele pode executar. Muitas vezes eu acho o Princípio do Make Badass útil para encontrar o equilíbrio, combinando-o com o Princípio do Mago Mínimo.