Le principe de responsabilité unique
("chaque classe ne devrait avoir qu'une seule responsabilité; en d'autres termes, chaque classe devrait avoir une et une seule raison de changer")
Je ne suis pas d'accord. Je pense qu'une méthode ne doit avoir qu'une raison de changer et que toutes les méthodes d'une classe doivent avoir une relation logique entre elles , mais la classe elle-même peut en réalité faire plusieurs choses (liées).
D'après mon expérience, ce principe est trop souvent appliqué avec trop de zèle et vous aboutissez à de nombreuses petites classes à une méthode. Les deux magasins agiles où j'ai travaillé l'ont fait.
Imaginez si les créateurs de l'API .Net avaient eu ce genre de mentalité: plutôt que List.Sort (), List.Reverse (), List.Find (), etc., nous aurions des classes ListSorter, ListReverser et ListSearcher!
Plutôt que de me disputer davantage contre le PÉR (qui en soi n’est pas terrible en théorie) , je vais partager quelques-unes de mes longues expériences anecdotiques:
À un endroit où j’ai travaillé, j’ai écrit un solveur de flux max très simple composé de cinq classes: un nœud, un graphe, un créateur de graphes, un solveur de graphes et une classe permettant d’utiliser les créateurs / solveurs de graphes pour résoudre un problème. problème du monde réel. Aucun n'était particulièrement complexe ou long (le solveur était de loin le plus long à environ 150 lignes). Cependant, il a été décidé que les classes avaient trop de «responsabilités», alors mes collègues se sont mis à la refactorisation du code. Quand ils ont fini, mes 5 classes ont été étendues à 25 classes, dont le nombre total de lignes de code était plus du triple de ce qu’elles étaient à l’origine. Le flux du code n'était plus évident, pas plus que l'objectif des nouveaux tests unitaires; J'avais maintenant du mal à comprendre ce que mon propre code faisait.
Au même endroit, presque toutes les classes n’avaient qu’une seule méthode (sa seule "responsabilité"). Suivre le déroulement du programme était presque impossible, et la plupart des tests unitaires consistaient à vérifier que cette classe appelait du code provenant d' une autre classe , dont le but était également un mystère pour moi. Il y avait littéralement des centaines de classes où il aurait fallu (IMO) seulement des dizaines. Chaque classe ne faisait qu'une "chose" , mais même avec des conventions de nommage telles que "AdminUserCreationAttemptorFactory" , il était difficile de dire la relation entre les classes.
À un autre endroit (qui avait également la mentalité classes-devrait-avoir-seulement-une-méthode ), nous essayions d'optimiser une méthode qui prenait 95% du temps au cours d'une certaine opération. Après (plutôt bêtement) l’optimiser un peu, j’ai tourné mon attention vers pourquoi on l’appelait des bajillions de fois. Il était appelé dans une boucle d'une classe ... dont la méthode était appelée dans une boucle d'une autre classe .. qui était également appelée dans une boucle ..
En tout, il y avait cinq niveaux de boucles répartis sur 13 classes (sérieusement). Il était impossible de déterminer ce qu’une classe faisait réellement en la regardant: vous deviez dessiner un graphe mental de ses méthodes, des méthodes appelées par ces méthodes, et ainsi de suite. Si tout avait été regroupé dans une seule méthode, il n'aurait fallu que 70 lignes de long avec notre méthode par problème imbriquée dans cinq niveaux de boucles immédiatement évidents.
Ma demande de refactoriser ces 13 classes en une seule classe a été refusée.