Zasada jednolitej odpowiedzialności
(„każda klasa powinna mieć tylko jedną odpowiedzialność; innymi słowy, każda klasa powinna mieć jeden i tylko jeden powód do zmiany”)
Nie zgadzam się. Myślę, że metoda powinna mieć tylko jeden powód do zmiany, a wszystkie metody w klasie powinny mieć logiczny związek ze sobą , ale sama klasa może faktycznie robić kilka (powiązanych) rzeczy.
Z mojego doświadczenia wynika, że ta zasada zbyt często stosuje się zbyt gorliwie, co kończy się wieloma drobnymi klasami opartymi na jednej metodzie. Zrobiły to oba zwinne sklepy, w których pracowałem.
Wyobraź sobie, że twórcy interfejsu API .Net mieli taką mentalność: zamiast List.Sort (), List.Reverse (), List.Find () itp. Mielibyśmy klasy ListSorter, ListReverser i ListSearcher!
Zamiast sprzeczać się już z SRP (co samo w sobie nie jest okropne) , podzielę się kilkoma moimi odwiecznymi anegdotycznymi doświadczeniami:
W jednym miejscu, w którym pracowałem, napisałem bardzo prosty solver o maksymalnym przepływie, który składał się z pięciu klas: węzła, wykresu, kreatora grafów, solvera grafów i klasy do używania kreatora grafów / solverów do rozwiązywania problem w świecie rzeczywistym. Żadna z nich nie była szczególnie złożona ani długa (solver był zdecydowanie najdłuższy przy ~ 150 liniach). Zdecydowano jednak, że klasy mają zbyt wiele „obowiązków”, więc moi współpracownicy przystąpili do refaktoryzacji kodu. Kiedy skończyli, moje 5 klas zostało poszerzonych do 25 klas, których łączna liczba linii kodu była ponad trzykrotnie większa niż pierwotnie. Przepływ kodu nie był już oczywisty, podobnie jak cel nowych testów jednostkowych; Trudno mi było zrozumieć, co zrobił mój własny kod.
W tym samym miejscu prawie każda klasa miała tylko jedną metodę (jej jedyna „odpowiedzialność”). Postępowanie w ramach programu było prawie niemożliwe, a większość testów jednostkowych polegała na testowaniu tej klasy kodu z innej klasy , których oba cele były dla mnie równie tajemnicą. Były dosłownie setki klas, w których powinno być (IMO) tylko kilkadziesiąt. Każda klasa zrobiła tylko jedną „rzecz” , ale nawet przy konwencjach nazewnictwa, takich jak „AdminUserCreationAttemptorFactory” , trudno było określić związek między klasami.
W innym miejscu (które miało również mentalność klas, które powinny mieć tylko jedną metodę ), próbowaliśmy zoptymalizować metodę, która zajęła 95% czasu podczas pewnej operacji. Po (raczej głupiej) optymalizacji, zwróciłem uwagę na to, dlaczego nazywano to bajillion razy. Został wywołany w pętli w klasie ... której metoda została wywołana w pętli w innej klasie .. która również została wywołana w pętli ..
W sumie pięć poziomów pętli rozłożonych na 13 klas (poważnie). To, co właściwie robiła jedna klasa, było niemożliwe do ustalenia na podstawie samego jej spojrzenia - trzeba było naszkicować mentalny wykres tego, jakie metody wywołał i jakie metody te metody wywołały i tak dalej. Gdyby wszystko zostało połączone w jedną metodę, miałby tylko około 70 linii długości, a nasza metoda problemowa byłaby osadzona w pięciu natychmiast oczywistych poziomach pętli.
Moja prośba o przekształcenie tych 13 klas w jedną klasę została odrzucona.