Atualmente, não acho útil debater sobre o que constitui e o que não constitui uma única responsabilidade ou uma única razão para mudar. Eu proporia um Princípio Mínimo de Luto em seu lugar:
Princípio Mínimo de Luto: o código deve procurar minimizar sua probabilidade de exigir alterações ou maximizar a facilidade de alteração.
Como é isso? Não é necessário que um cientista de foguetes descubra por que isso pode ajudar a reduzir os custos de manutenção e, esperançosamente, não deve ser um ponto de debate sem fim, mas, como no SOLID em geral, não é algo para aplicar às cegas em todos os lugares. É algo a considerar ao equilibrar trade-offs.
Quanto à probabilidade de exigir alterações, isso diminui com:
- Bom teste (confiabilidade aprimorada).
- Envolver apenas o código mínimo necessário para fazer algo específico (isso pode incluir a redução de acoplamentos aferentes).
- Apenas torne o código durão no que faz (consulte Tornar o princípio durão).
Quanto à dificuldade de fazer alterações, ela aumenta com os acoplamentos eferentes. O teste introduz acoplamentos eferentes, mas melhora a confiabilidade. Feito bem, geralmente faz mais bem do que mal e é totalmente aceitável e promovido pelo Princípio Mínimo de Luto.
Faça o princípio de Badass: as classes usadas em muitos lugares devem ser incríveis. Eles devem ser confiáveis, eficientes se isso estiver relacionado à sua qualidade, etc.
E o princípio Make Badass está vinculado ao princípio de luto mínimo, uma vez que as coisas mais duras encontrarão uma menor probabilidade de exigir mudanças do que as que são péssimas no que fazem.
Eu começaria apontando o paradoxo mencionado acima e depois indicaria que o SRP é altamente dependente do nível de granularidade que você deseja considerar e que, se você for suficientemente longe, qualquer classe que contenha mais de uma propriedade ou um método viola isto.
Do ponto de vista do SRP, uma classe que quase nada faz 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. É o ZRP!
Exceto que eu sugeriria uma violação flagrante do princípio Make Badass. Também é absolutamente inútil. Algo que faz tão pouco não pode esperar ser durão. Tem muito pouca informação (TLI). E, naturalmente, quando você tem algo que é TLI, ele não pode fazer nada realmente significativo, nem mesmo com as informações que encapsula; portanto, deve vazá-las para o mundo exterior, na esperança de que outra pessoa faça algo significativo e durão. E esse vazamento é bom para algo que apenas agrega dados e nada mais, mas esse limite é a diferença que eu vejo entre "dados" e "objetos".
Claro que algo que é TMI também é ruim. Podemos colocar todo o software em uma classe. Pode até ter apenas um run
método. E alguém pode até argumentar que agora há um motivo muito amplo para mudar: "Essa classe só precisará ser alterada se o software precisar de melhorias". Estou sendo bobo, mas é claro que podemos imaginar todos os problemas de manutenção com isso.
Portanto, há um ato de equilíbrio quanto à granularidade ou grosseria dos objetos que você cria. Costumo julgá-lo pela quantidade de informações que você deve vazar para o mundo exterior e pela funcionalidade significativa que ela pode executar. Costumo achar o princípio Make Badass útil para encontrar o equilíbrio ao combiná-lo com o princípio do luto mínimo.