El principio de responsabilidad única
("cada clase debe tener una sola responsabilidad; en otras palabras, cada clase debe tener una, y solo una, razón para cambiar")
Estoy en desacuerdo. Creo que un método debería tener una sola razón para cambiar, y todos los métodos en una clase deberían tener una relación lógica entre sí , pero la clase en sí misma podría hacer varias cosas (relacionadas).
En mi experiencia, este principio con demasiada frecuencia se aplica con demasiado entusiasmo, y terminas con muchas clases pequeñas de un método. Ambas tiendas ágiles en las que he trabajado han hecho esto.
¡Imagínese si los creadores de la API .Net hubieran tenido este tipo de mentalidad: en lugar de List.Sort (), List.Reverse (), List.Find () etc., tendríamos las clases ListSorter, ListReverser y ListSearcher!
En lugar de seguir discutiendo en contra del SRP (que en sí mismo no es terrible en teoría) , compartiré algunas de mis experiencias anecdóticas:
En un lugar donde trabajé, escribí un solucionador de flujo máximo muy simple que constaba de cinco clases: un nodo, un gráfico, un creador de gráficos, un solucionador de gráficos y una clase para usar el creador de gráficos / solucionadores para resolver un problema del mundo real Ninguno fue particularmente complejo o largo (el solucionador fue, con mucho, el más largo con ~ 150 líneas). Sin embargo, se decidió que las clases tenían demasiadas "responsabilidades", por lo que mis compañeros de trabajo comenzaron a refactorizar el código. Cuando terminaron, mis 5 clases se habían ampliado a 25 clases, cuyas líneas de código totales eran más del triple de lo que eran originalmente. El flujo del código ya no era obvio, ni el propósito de las nuevas pruebas unitarias; Ahora me resultaba difícil descubrir qué hacía mi propio código.
En el mismo lugar, casi todas las clases tenían un solo método (su única "responsabilidad"). Seguir el flujo dentro del programa era casi imposible, y la mayoría de las pruebas unitarias consistían en probar que esta clase llamaba código de otra clase , cuyo propósito era igualmente un misterio para mí. Había literalmente cientos de clases donde debería haber (IMO) solo docenas. Cada clase hizo solo una "cosa" , pero incluso con convenciones de nomenclatura como "AdminUserCreationAttemptorFactory" , fue difícil distinguir la relación entre las clases.
En otro lugar (que también tenía la mentalidad de clases-debería-tener-solo-un-método ), estábamos tratando de optimizar un método que ocupaba el 95% del tiempo durante una determinada operación. Después (optimistamente) de optimizarlo un poco, volví mi atención hacia por qué se llamaba un millón de veces. Se llamaba en un bucle en una clase ... cuyo método se llamaba en un bucle en otra clase ... que también se llamaba en un bucle ...
En total, hubo cinco niveles de bucles repartidos en 13 clases (en serio). Lo que estaba haciendo cualquier clase en realidad era imposible de determinar con solo mirarlo: había que dibujar un gráfico mental de qué métodos llamaba, y qué métodos llamaban esos métodos, y así sucesivamente. Si todo se hubiera agrupado en un solo método, solo habría tenido unas 70 líneas con nuestro método problemático anidado dentro de cinco niveles de bucles inmediatamente obvios.
Mi solicitud para refactorizar esas 13 clases en una sola clase fue denegada.