Jaka jest dobra praktyka kodowania, kiedy należy utworzyć funkcję / metodę dla małych powtarzalnych segmentów kodu?

12

Wiele razy podczas pisania większych programów pytałem o to, ile kopii i past ma sens, aby umieścić kod w funkcji lub metodzie i jaka jest dobra zasada? Korzystam z praktycznej reguły składającej się z czterech lub więcej linii i pojawiają się więcej niż dwa razy, a następnie tworzę prostą funkcję / metodę zawierającą ten kod. Czy możesz wymyślić lepszą praktykę lub zaoferować jakieś wskazówki? Jest to raczej ogólne pytanie dotyczące wzoru niż pytanie dotyczące konkretnego języka.


źródło

Odpowiedzi:

29

Używam funkcji częściowo jako sposobu na udokumentowanie kodu. Wywołanie funkcji o znaczącej nazwie ułatwia zrozumienie kodu. W niektórych przypadkach nawet funkcja z jedną linią ma sens.

Na przykład w „Czystym kodzie” Robert C. Martin podaje następujący przykład: Który wolisz zobaczyć? To:

// Check to see if the employee is eligible for full benefits
if ((employee.flags & HOURLY_FLAG) &&
    (employee.age > 65))

Albo to?

if (employee.isEligibleForFullBenefits())

Nie zawsze się z nim zgadzam, ale w tym przypadku się zgadzam. Kod powinien być czytelny nie tylko wtedy, gdy go napiszesz i znasz każdy szczegół, ale także o 21:00, kiedy musisz naprawić błędy w cudzym kodzie. Wpatrywanie się w długi stan i próba wykrycia wszystkich podwójnych negatywów nie jest zalecane. Jeśli możesz po prostu nadać mu nazwę (nie tylko warunki, ale każdy napisany kod), staje się to o wiele prostsze.

Nigdy nie żałowałem, że wprowadziłem coś w funkcję, a jeśli martwisz się wydajnością, najpierw profil.

omrib
źródło
2
Postępowanie zgodnie z tą prostą praktyką pozwoli ostatecznie napisać kod aplikacji na stosunkowo wysokim poziomie. Małe funkcje są gromadzone w małe klasy i wkrótce konwertujesz specyfikacje funkcjonalne do kodu prawie słowo w słowo.
kevin cline,
11
Podobał mi się ten przykład. Nagle nie potrzebujesz już tego komentarza. Jest to ogólna zasada : jeśli twój komentarz można przekształcić w nazwę zmiennej lub funkcji, zrób to!
Karoly Horvath,
Zgadzam się z omrib, tutaj często chodzi o czyszczenie kodu - co czyni go bardziej czytelnym niż jakakolwiek inna zasada. Jeśli w końcu coś ponownie wykorzystam, wyodrębnię to do metody. Jednak moje IDE i narzędzia często w tym pomagają, więc jest to łatwe i szybkie.
Travis,
+1 Ten rodzaj kodu może być nawet szybszy, przynajmniej jeśli wymaga edycji JIT - płacisz tylko za to, czego używasz.
Job
1
znane również jako intencje ujawniające nazwy .
rwong
13

Istnieje powszechne nieporozumienie, że wywołania funkcji należy wykonywać tylko w celu uniknięcia powtarzających się segmentów kodu. Zasadą ogólną jest to, że każda logiczna jednostka pracy powinna zostać przekształcona w funkcję, nawet jeśli jest używana tylko w jednym miejscu. Zwykle prowadzi to do lepszej czytelności i pozwala napisać kod samodokumentujący, w którym nazwy funkcji zastępują komentarze i nie trzeba pisać dodatkowych komentarzy wyjaśniających, co robisz.

Lie Ryan
źródło
1
Zobacz, na jakie długości pójdą programiści, aby uniknąć pisania komentarzy?
Alger,
1
@Berger jak powinni
MatrixFrog
6

Jeśli jest używany w więcej niż jednym miejscu, i

  • może się zmienić, lub
  • trudno jest to naprawić

następnie uczyń to funkcją lub metodą. Długie fragmenty powtarzającego się kodu, z mojego doświadczenia, naturalnie będą należeć do jednej z tych kategorii (zwykle pierwszej, ale potem kategorie bardzo często się pokrywają;). Oczywiście wszystko, co musi znajdować się w interfejsie, jest również funkcją / metodą samą w sobie.

Fred Foo
źródło
3
Pytanie brzmi: dlaczego nie napisałbyś funkcji dla często powtarzanego fragmentu kodu, nawet jeśli poprawne wykonanie lub zmiana nie byłyby trudne? (Moja ogólna zasada: jeśli powtarza się i dłużej niż wywoływanie funkcji, uczyń ją funkcją)
Winston Ewert
Poszedłbym jeszcze dalej. Jako programista musisz wyeliminować wszelkiego rodzaju powtórzenia . Niezależnie od tego, czy znajduje się w bazie danych (normalizacja), niektóre testy ręczne (zamień na testy jednostkowe) lub wdrożenie (zautomatyzuj).
Karoly Horvath,
@Winston: zależy to od używanego języka. Nie każdy konstrukt może zostać w naturalny sposób uchwycony jako funkcja, funkcja może zająć więcej miejsca niż oryginalny kod (pomyśl C i zwróć za pomocą wskaźnika), wywołania funkcji mogą spowodować narzut.
Fred Foo,
@ larsman, jestem ciekawy, o czym mówisz przez „(pomyśl C i wróć wskaźnikiem)”. Ale to, co mówisz, jest tym, co próbowałem osiągnąć przy pomocy mojej ogólnej zasady. Wywołanie funkcji musi być łatwiejsze (tj. Naturalnie przechwytywanie i zajmowanie mniejszej ilości miejsca) niż implementacja zawartości funkcji.
Winston Ewert,
Jeśli kawałek kodu oblicza wiele wartości, powiedzmy float x, int ya double densitynastępnie skonfigurowanie tych obliczeń jako funkcji C może być trudniejsze niż zwykłe powtarzanie kodu, ponieważ musisz wymyślić sposób, aby uzyskać wszystkie trzy wartości. Jeśli same powtarzane obliczenia są trywialne, czasem lepiej pozostawić je w wierszu.
Fred Foo,
4

Niemal zawsze, szczególnie jeśli każdy duplikat reprezentuje tę samą operację z koncepcyjnego punktu widzenia. Jeśli jest wykonywany w ten sam sposób, ale na różnych typach, wykonaj ogólną implementację.

Jedynym powodem, dla którego nie mogę tego wymyślić, jest konserwacja: czasem wygodniej byłoby uniknąć tworzenia zależności między oddzielnymi rzeczami, nawet kosztem pewnego powielania.

Nicola Musatti
źródło
Uważaj na pisanie kaczek, jeśli na razie implementacja jest podobna, ale funkcjonalność jest faktycznie inna, to połączenie tych dwóch sprawi, że rozpaczliwe będzie irytujące. Zwłaszcza w językach ze słabym wsparciem IDE (hej, pracuję w C ++ ...)
Matthieu M.,
Z drugiej strony, rozdzielając je, masz dwie funkcje, które sprawdzają to samo, połowę szansy na wykonanie kodu, dwa miejsca, w których ten sam błąd może się wkraść i musisz pamiętać o naprawieniu tej, w której błąd nie został jeszcze wykryty. Chciałbym nadal pracować w C ++, pomimo słabej obsługi IDE ;-)
Nicola Musatti
1

Poszukiwanie „ refaktoryzacji ” doprowadzi cię do wielu zasobów dla „najlepszych praktyk” branży dla tego bardzo powszechnego procesu. Dość sławny artykuł „ Raz i tylko raz” jest świetnym odniesieniem historycznym wyjaśniającym, co niektórzy uważają za „najlepsze praktyki” w związku z wątpliwościami wynikającymi z pytania. Ponadto, nawet bardziej ogólna koncepcja jest znana jako Don't Repeat Yourself (DRY) . Aby uzyskać naprawdę dogłębny zestaw odpowiedzi na twoje pytanie, przeczytaj świetny klasyk Martina Fowlera Refactoring: Improving Design of Existing Code , który zawiera jedne z najbardziej znanych porad dotyczących refaktoryzacji , które intuicyjnie próbujesz osiągnąć !

John Tobler
źródło
0

Jeśli kod zostanie dokładnie powtórzony w więcej niż jednym miejscu, a powtarzająca się sekcja nie zmieni się w najbliższej przyszłości, wówczas podzielę go na funkcję.

Steven D.
źródło
1
jeśli to się zmieni, jeszcze więcej powodów, by to zreformować. Wtedy będziesz musiał to zmienić tylko raz
SHug
0

Zależy to od charakteru spójności powtarzanego kodu. Jeśli powtarzająca się sekcja kodu wykonuje określoną funkcję, to jest doskonałym kandydatem do przekształcenia w metodę, częściowo z powodu zasady DRY , częściowo dlatego, że jeśli funkcja wymaga optymalizacji lub korekty, to jest tylko jedna sekcja kodu do obsługi.

Jeśli skojarzenie jest przypadkowe, lepiej jest powtórzyć kod niż przekształcić go w metodę. Jeśli musisz dodać coś na środku jednej z sekwencji kodu, aby zaspokoić jedno z zastosowań tego fragmentu kodu, jeśli jest to metoda, wprowadzona zmiana może wpłynąć na inne zastosowania tej metody.

Zobacz artykuł w Wikipedii na temat spójności kodu .

Jay Elston
źródło
jeśli skojarzenie wygląda na przypadkowe, prawdopodobne jest, że oba procesy mają wspólny pomysł i prawdopodobnie powinieneś zbadać, czy te dwa procesy są rzeczywiście dwoma aspektami tego samego. Najczęściej tak jest.
Lie Ryan,
0

Musisz rozróżnić funkcje w sensie programowania strukturalnego i metody klasy.

W twoim przykładzie pokazałeś metodę, która jako taka nie powinna być kodowana w linii.

może być konieczne sprawdzenie poprawności ciągu, aby sprawdzić, czy jest to liczba, czy nie, w tym przypadku używasz funkcji i zastosowanie ma większość poprzednich odpowiedzi.

To rozróżnienie jest ważne szczególnie w dużych projektach.

W miarę możliwości staraj się oddzielać reguły biznesowe (czyli metody) od algorytmów obliczeniowych (które są czysto funkcjami programowania).

Bez szans
źródło