Il principio di responsabilità unica
("ogni classe dovrebbe avere una sola responsabilità; in altre parole, ogni classe dovrebbe avere una, e una sola, ragione per cambiare")
Non sono d'accordo. Penso che un metodo dovrebbe avere solo una ragione per cambiare, e tutti i metodi in una classe dovrebbero avere una relazione logica tra loro , ma la classe stessa potrebbe effettivamente fare diverse cose (correlate).
Nella mia esperienza, questo principio troppo spesso viene applicato in modo troppo zelante e si finisce con molte piccole classi con un metodo. Entrambi i negozi agili in cui ho lavorato lo hanno fatto.
Immagina se i creatori dell'API .Net avessero avuto questo tipo di mentalità: piuttosto che List.Sort (), List.Reverse (), List.Find () ecc., Avremmo le classi ListSorter, ListReverser e ListSearcher!
Piuttosto che litigare più contro l'SRP (che in sé non è terribile in teoria) , condividerò alcune delle mie esperienze aneddotiche a lungo termine:
In un posto in cui ho lavorato, ho scritto un risolutore di flusso massimo molto semplice che consisteva in cinque classi: un nodo, un grafico, un creatore di grafici, un risolutore di grafici e una classe per utilizzare il creatore di grafici / solutori per risolvere un problema del mondo reale. Nessuno era particolarmente complesso o lungo (il solutore era di gran lunga il più lungo con circa 150 righe). Tuttavia, è stato deciso che le classi avevano troppe "responsabilità", quindi i miei colleghi hanno iniziato a riformattare il codice. Al termine, le mie 5 classi erano state estese a 25 classi, le cui linee di codice totali erano più del triplo di quelle che erano in origine. Il flusso del codice non era più ovvio, né lo scopo dei nuovi test unitari; Ora ho avuto difficoltà a capire cosa facesse il mio codice.
Allo stesso posto, quasi ogni classe aveva un solo metodo (la sua unica "responsabilità"). Seguire il flusso all'interno del programma era quasi impossibile e la maggior parte dei test unitari consisteva nel verificare che questa classe chiamasse codice da un'altra classe , entrambi i cui scopi erano ugualmente un mistero per me. C'erano letteralmente centinaia di classi in cui avrebbero dovuto esserci (IMO) solo dozzine. Ogni classe ha fatto solo una "cosa" , ma anche con convenzioni di denominazione come "AdminUserCreationAttemptorFactory" , era difficile dire la relazione tra le classi.
In un altro posto (che aveva anche la mentalità class-have-have-only-one-method ), stavamo cercando di ottimizzare un metodo che impiegava il 95% del tempo durante una certa operazione. Dopo averlo (piuttosto stupidamente) ottimizzato un po ', ho rivolto la mia attenzione al perché veniva chiamato un bajillion volte. Veniva chiamato in un ciclo in una classe ... il cui metodo veniva chiamato in un ciclo in un'altra classe ... che veniva anche chiamato in un ciclo ...
Tutto sommato, c'erano 13 livelli di loop distribuiti su 13 classi (sul serio). Ciò che una classe stava effettivamente facendo era impossibile da determinare semplicemente osservandolo: dovevi tracciare un grafico mentale di quali metodi chiamava, quali metodi chiamavano quei metodi e così via. Se fosse stato tutto sommato in un unico metodo, sarebbe stato lungo solo circa 70 righe con il nostro metodo problematico annidato all'interno di cinque livelli immediatamente evidenti di loop.
La mia richiesta di trasformare queste 13 classi in una classe è stata respinta.