No me parece útil en estos días debatir sobre qué constituye y qué no constituye una sola responsabilidad o una sola razón para cambiar. Yo propondría un Principio de pena mínima en su lugar:
Principio de pena mínima: el código debe buscar minimizar su probabilidad de requerir cambios o maximizar la facilidad de cambio.
¿Cómo es eso? No debería recurrir a un científico espacial para descubrir por qué esto puede ayudar a reducir los costos de mantenimiento y, con suerte, no debería ser un punto de debate interminable, pero como con SOLID en general, no es algo que se aplique a ciegas en todas partes. Es algo a tener en cuenta al equilibrar las compensaciones.
En cuanto a la probabilidad de requerir cambios, eso se reduce con:
- Buenas pruebas (fiabilidad mejorada).
- Involucrando solo el código mínimo requerido para hacer algo específico (esto puede incluir la reducción de acoplamientos aferentes).
- Simplemente haciendo que el código sea rudo en lo que hace (ver Principio Make Badass).
En cuanto a la dificultad de realizar cambios, aumenta con acoplamientos eferentes. Las pruebas introducen acoplamientos eferentes pero mejoran la fiabilidad. Bien hecho, generalmente hace más bien que mal y es totalmente aceptable y promovido por el Principio Mínimo de Pena.
Haga el principio de Badass: las clases que se usan en muchos lugares deberían ser increíbles. Deben ser confiables, eficientes si eso se vincula con su calidad, etc.
Y el Principio Make Badass está vinculado al Principio Mínimo de Pena, ya que las cosas rudas encontrarán una menor probabilidad de requerir cambios que las cosas que apestan a lo que hacen.
Habría comenzado señalando la paradoja mencionada anteriormente, y luego indicaría que el SRP es altamente dependiente del nivel de granularidad que desea considerar y que si lo lleva lo suficientemente lejos, cualquier clase que contenga más de una propiedad o un método viola eso.
Desde el punto de vista de SRP, una clase que apenas hace algo ciertamente tendría solo una (a veces cero) razones para cambiar:
class Float
{
public:
explicit Float(float val);
float get() const;
void set(float new_val);
};
¡Eso prácticamente no tiene razones para cambiar! Es mejor que SRP. Es ZRP!
Excepto que sugeriría que es una violación flagrante del Principio Make Badass. También es absolutamente inútil. Algo que hace tan poco no puede esperar ser rudo. Tiene muy poca información (TLI). Y, naturalmente, cuando tienes algo que es TLI, no puede hacer nada realmente significativo, ni siquiera con la información que encapsula, por lo que tiene que filtrarlo al mundo exterior con la esperanza de que alguien realmente haga algo significativo y rudo. Y esa fuga está bien para algo que solo pretende agregar datos y nada más, pero ese umbral es la diferencia que veo entre "datos" y "objetos".
Por supuesto, algo que es TMI también es malo. Podríamos poner todo nuestro software en una clase. Incluso puede tener un solo run
método. Y alguien podría incluso argumentar que ahora tiene una razón muy amplia para cambiar: "Esta clase solo tendrá que cambiarse si el software necesita mejoras". Estoy siendo tonto, pero por supuesto podemos imaginar todos los problemas de mantenimiento con eso.
Por lo tanto, existe un acto de equilibrio en cuanto a la granularidad o aspereza de los objetos que diseña. A menudo lo juzgo por la cantidad de información que tiene que filtrar al mundo exterior y cuánta funcionalidad significativa puede realizar. A menudo encuentro útil el Principio Make Badass para encontrar el equilibrio mientras lo combino con el Principio Mínimo de Pena.