Wyczyść kod: funkcje z kilkoma parametrami [zamknięte]

49

Przeczytałem pierwsze rozdziały Czystego kodu autorstwa Roberta C. Martina i wydaje mi się, że jest całkiem niezły, ale mam wątpliwości, w jednej części wspomniano, że dobrze (poznawczo), że funkcje powinny mieć jak najmniej parametrów jak to możliwe, sugeruje nawet, że 3 lub więcej parametrów to za dużo dla funkcji (co uważam za bardzo przesadzone i idealistyczne), więc zacząłem się zastanawiać ...

Zarówno praktyki używania zmiennych globalnych, jak i przekazywanie wielu argumentów na temat funkcji byłyby złymi praktykami programowania, ale użycie zmiennych globalnych może znacznie zmniejszyć liczbę parametrów w funkcjach ...

Chciałem więc usłyszeć, co o tym sądzisz. Czy warto używać zmiennych globalnych, aby zmniejszyć liczbę parametrów funkcji, czy nie? W jakich przypadkach byłoby to?

Myślę, że zależy to od kilku czynników:

  • Rozmiar kodu źródłowego.
  • Liczba parametrów w średniej funkcji.
  • Liczba funkcji
  • Częstotliwość, w której używane są te same zmienne.

Moim zdaniem, jeśli rozmiar kodu źródłowego jest stosunkowo mały (jak mniej niż 600 wierszy kodu), istnieje wiele funkcji, te same zmienne są przekazywane jako parametry, a funkcje mają wiele parametrów, wówczas warto byłoby użyć zmiennych globalnych, ale ja chciałbym wiedzieć...

  • Czy podzielasz moją opinię?
  • Co sądzisz o innych przypadkach, w których kod źródłowy jest większy itp.?

PS . Widziałem ten post , tytuły są bardzo podobne, ale nie pyta, co chcę wiedzieć.

OiciTrap
źródło
144
Nie sądzę, że alternatywą byłyby globały, ale zamiast tego konsolidacja argumentów w obiekty. Prawdopodobnie jest to raczej sugestia, która postLetter(string country, string town, string postcode, string streetAddress, int appartmentNumber, string careOf)jest śmierdzącą wersją postLetter(Address address). Kontynuuj czytanie książki, mam nadzieję, że powie coś takiego.
Nathan Cooper
3
@DocBrown Przyjąłem to pytanie, aby powiedzieć coś więcej niż wujek Bob mówi, że nie używaj więcej niż 3 parametrów, więc obejdę ten problem, używając zmiennych globalnych, prawda? :-) Myślę, że prawdopodobnie autor nie wie, że istnieją lepsze sposoby na obejście tego problemu - jak wspomniano w odpowiedziach poniżej.
bytedev
9
Nie więcej niż n parametrów jest ogólną zasadą (dla dowolnej wartości n), nie wytrawioną na diamentie. Nie myl dobrych rad z mandatem. Wiele parametrów to na ogół zapach kodu, w którym zbyt wiele dzieje się w jednej funkcji / metodzie. Ludzie unikali podziału na wiele funkcji, aby uniknąć dodatkowego obciążenia związanego z dodatkowymi połączeniami. Niewiele aplikacji jest już tak wymagających, a profiler może powiedzieć, kiedy i gdzie należy unikać dodatkowych połączeń.
Jared Smith
14
To pokazuje, co jest nie tak z tego rodzaju zasadą pozbawioną osądu: otwiera drzwi do „rozwiązań” pozbawionych osądu. Jeśli funkcja ma wiele argumentów, może wskazywać na nieoptymalny projekt, zwykle nie tylko funkcji, ale kontekst, w którym jest używana. Rozwiązaniem (jeśli jest potrzebne) jest próba zmiany kodu. Nie mogę dać ci prostej, ogólnej, pozbawionej osądu zasady, jak to zrobić, ale to nie znaczy, że „nie więcej niż N argumentów” jest dobrą zasadą.
sdenham
4
Jeśli masz zbyt wiele parametrów do funkcji, istnieje prawdopodobieństwo, że niektóre z nich są powiązane i powinny zostać zgrupowane w obiekt, który następnie staje się pojedynczym parametrem obejmującym wiele elementów danych. Jest tutaj trzecia opcja.

Odpowiedzi:

113

Nie podzielam twojej opinii. Moim zdaniem stosowanie zmiennych globalnych jest gorszą praktyką niż więcej parametrów, niezależnie od opisywanych cech. Moje rozumowanie jest takie, że więcej parametrów może utrudnić zrozumienie metody, ale zmienne globalne mogą powodować wiele problemów dla kodu, w tym słabą testowalność, błędy współbieżności i ścisłe sprzężenie. Bez względu na to, ile parametrów ma funkcja, z natury nie będzie miała takich samych problemów jak zmienne globalne.

... te same zmienne są przekazywane jako parametry

Może to być zapach designerski. Jeśli te same parametry są przekazywane do większości funkcji w systemie, może istnieć problem przekrojowy, którym należy się zająć, wprowadzając nowy komponent. Nie sądzę, aby przekazywanie tej samej zmiennej do wielu funkcji było rozsądnym uzasadnieniem wprowadzenia zmiennych globalnych.

W jednej edycji pytania wskazałeś, że wprowadzenie zmiennych globalnych może poprawić czytelność kodu. Nie zgadzam się. Użycie zmiennych globalnych jest ukryte w kodzie implementacji, podczas gdy parametry funkcji są zadeklarowane w podpisie. Funkcje powinny być idealnie czyste. Powinny działać tylko na podstawie swoich parametrów i nie powinny mieć żadnych skutków ubocznych. Jeśli masz czystą funkcję, możesz uzasadnić tę funkcję, patrząc tylko na jedną funkcję. Jeśli twoja funkcja nie jest czysta, musisz wziąć pod uwagę stan innych składników i trudniej jest ją zrozumieć.

Samuel
źródło
Ok, dobrze jest słyszeć inne opinie, ale o zapachu projektowym programuję w C problemy, które są rozwiązywane metodami sztucznej inteligencji i zwykle używam wielu funkcji, które prawie zawsze używają tych samych macierzy, tablic lub zmiennych (które Podaję parametry do funkcji), mówię to, ponieważ nie czuję, żebym mógł umieścić te zmienne we wspólnej koncepcji / rzeczy, takiej jak struct lub union, więc nie wiedziałbym, jak stworzyć lepszy projekt, dlatego myślę, że użycie zmiennych globalnych w tym przypadku może być warte, ale najprawdopodobniej się mylę.
OiciTrap
1
To nie brzmi jak problem z projektem. Nadal uważam, że przekazywanie parametrów do funkcji jest najlepszym projektem. W systemie AI, który opisujesz, przydałoby się napisać testy jednostkowe w celu przetestowania elementów systemu, a najłatwiej to zrobić za pomocą parametrów.
Samuel
96
Inne parametry sprawiają podprogram trudniejsze do zrozumienia, zmienne globalne zrobić cały program, czyli wszystkie podprogramy trudniejsze do zrozumienia.
Jörg W Mittag,
2
Utrzymuję bazę kodu, w której niektóre funkcje pobierają kilkanaście parametrów. To ogromna strata czasu - za każdym razem, gdy potrzebuję wywołać funkcję, muszę otworzyć ten plik w innym oknie, aby wiedzieć, w jakiej kolejności należy podać parametry. Gdybym użył IDE, które dało mi coś w rodzaju inteligencji, lub gdybym użył języka, który nazwał parametry, to nie byłoby tak źle, ale kto może pamiętać, w jakiej kolejności jest tuzin parametrów dla wszystkich tych funkcji?
Jerry Jeremiah
6
Odpowiedź jest poprawna w tym, co mówi, niemniej jednak wydaje się, że OP nieporozumienie co do rekomendacji w „Czystym Kodzie” jest rzeczą oczywistą. Jestem pewien, że w tej książce nie ma zalecenia, aby zastąpić parametry funkcji globałami.
Doc Brown
68

Powinieneś unikać zmiennych globalnych, takich jak plaga .

Nie ograniczałbym twardej liczby argumentów (np. 3 lub 4), ale jeśli chcesz , chcesz je ograniczyć do minimum.

Użyj structs (lub obiektów w C ++), aby pogrupować zmienne w jedną całość i przekazać je (przez odniesienie) do funkcji. Zwykle funkcja otrzymuje strukturę lub obiekt (zawierający kilka różnych rzeczy) wraz z kilkoma innymi parametrami, które każą funkcji coś zrobić struct.

Aby uzyskać przyjemny, czysty, modułowy kod, staraj się trzymać zasady pojedynczej odpowiedzialności . Zrób to ze swoimi strukturami (lub obiektami), funkcjami i plikami źródłowymi. Jeśli to zrobisz, naturalna liczba parametrów przekazanych do funkcji będzie oczywista.

Robert Bristol-Johnson
źródło
5
Jaka jest zasadnicza różnica między przekazywaniem dziesiątek parametrów ukrytych w strukturze a przekazywaniem ich jawnie?
Ruslan,
21
@ Ruslan Spójność.
abuzittin gillifirca
9
Bardziej prawdopodobne jest, że funkcja zostanie przekształcona na mniejsze funkcje, ponieważ można przekazać jeden parametr do podfunkcji zamiast dziesiątek parametrów. I mniejsze ryzyko pomieszania parametrów, jeśli użyjesz argumentów pozycyjnych.
Hans Olsson,
8
W porządku, ale musisz zapewnić spójność w Strukturach - upewnij się, że parametry zgrupowane w Strukturze są „powiązane”. W niektórych okolicznościach możesz użyć więcej niż jednej Struktury.
Andrew Dodds
8
@abuzittingillifirca Nie uzyskujesz spójności automatycznie. Jeśli jedynym uzasadnieniem umieszczenia parametrów w strukturze jest przekazanie ich do określonej funkcji, to spójność jest prawdopodobnie iluzoryczna.
sdenham
55

Mówimy o obciążeniu poznawczym, a nie o składni. Pytanie brzmi: co to jest parametr w tym kontekście?

Parametr jest wartością, która wpływa na zachowanie funkcji. Im więcej parametrów, tym więcej możliwych kombinacji wartości, tym trudniejsze jest rozumowanie na temat funkcji.

W tym sensie zmienne globalne używane przez funkcję parametrami. Są to parametry, które nie pojawiają się w jego sygnaturze, które mają problemy z kolejnością budowy, kontrolą dostępu i problemami remanencji.

O ile wspomniany parametr nie jest nazywany problemem przekrojowym , to jest stanem obejmującym cały program, z którego korzysta wszystko, ale nic się nie zmienia (np. Obiekt rejestrujący), nie należy zastępować parametrów funkcji zmiennymi globalnymi. Nadal byłyby parametrami, ale paskudniejsze.

Quentin
źródło
11
Dla Ciebie +1, czy to toalety czy komody, śmierdzą tak samo. Dobra robota, wskazując wilka w owczej skórze.
Jared Smith
1
+1 za stwierdzenie, że zarówno wiele parmsów, jak i globalne zmienne są złe. Ale chcę coś wyjaśnić. W większości języków prymitywne parametry są domyślnie przekazywane przez wartość (Java), aw innych można je przekazywać jawnie (PL / SQL). Z drugiej strony globalne operacje podstawowe są zawsze dostępne przez odniesienie (że tak powiem). Zatem parametry, przynajmniej pierwotne, są zawsze bezpieczniejsze niż zmienne globalne. Chociaż oczywiście posiadanie więcej niż dwóch lub trzech parametrów jest zapachem, a posiadanie dwunastu parametrów jest ogromnym zapachem, który należy ponownie przetworzyć.
Tulains Córdova
4
Oczywiście, zmienna globalna JEST parametrem ukrytym.
Bill K
+1 Do twojego punktu, widziałem symulacje MATLAB, które do przekazywania danych opierają się na zmiennych globalnych. Wynik był całkowicie nieczytelny, ponieważ tak trudno było stwierdzić, które zmienne są parametrami dla której funkcji.
Cort Ammon
34

IMHO twoje pytanie jest oparte na nieporozumieniu. W „Czystym kodzie” Bob Martin nie sugeruje zastępowania powtarzających się parametrów funkcji globałami, co byłoby naprawdę okropną radą. Sugeruje zastąpienie ich zmiennymi składowymi prywatnymi klasy funkcji. Proponuje także małe, spójne klasy (zwykle mniejsze niż 600 linii kodu, o których wspomniałeś), więc te zmienne składowe zdecydowanie nie są globalne.

Więc jeśli masz opinię w kontekście mniej niż 600 wierszy „warto byłoby użyć zmiennych globalnych” , wtedy doskonale podzielasz opinię wuja Boba. Oczywiście dyskusyjne jest, czy „3 parametry maksymalnie” to idealna liczba, i jeśli ta reguła czasami prowadzi do zbyt wielu zmiennych składowych, nawet w małych klasach. IMHO jest to kompromis, nie ma twardej i szybkiej zasady, gdzie wytyczyć granicę.

Doktor Brown
źródło
10
Nigdy nie zrozumiałem, dlaczego ktoś wolałby uczynić swoją klasę stanową poprzez upychanie parametrów w konstruktorze zamiast po prostu żyć z prawdziwym argumentem. To zawsze wydawało mi się ogromnym wzrostem złożoności. (Prawdziwym przykładem, jaki widziałem na ten temat, jest obiekt połączenia z bazą danych, który sprawił, że próba śledzenia stanu bazy danych przez program jest prawie niemożliwa w połączeniu z wstrzykiwaniem zależności). Być może jednak Clean Code ma więcej do powiedzenia na ten temat Przedmiot. Globały są oczywiście jeszcze gorszą opcją, jeśli chodzi o nadawanie stanom stanu.
jpmc26,
2
@ jpmc26: „wspaniały wzrost złożoności” można uzyskać tylko wtedy, gdy klasy stają się zbyt duże i otrzymują zbyt wiele zmiennych składowych, więc wynik nie jest już spójny.
Doc Brown
4
Myślę, że odpowiedź ignoruje trudność w zarządzaniu stanem (który może być nawet zmienny), który jest rozłożony na wiele klas. Gdy funkcja zależy nie tylko od argumentów, ale także od tego, jak obiekt został skonstruowany (lub nawet zmodyfikowany przez cały okres jego użytkowania), zrozumienie jego obecnego stanu podczas wykonywania określonego wywołania staje się trudniejsze. Teraz musisz wyśledzić konstrukcję innego obiektu, aby dowiedzieć się, co zrobi połączenie. Dodawanie zmiennych instancji aktywnie zwiększa stan programu, chyba że zbudujesz obiekt i natychmiast go wyrzucisz?
jpmc26,
3
@ jpmc26 Jednym ze wzorów, których używam regularnie podczas refaktoryzacji jest to, że konstruktor działa jak ustawienie kontekstu, a następnie argumenty metody są specyficzne dla akcji. Obiekt nie jest dokładnie stanowy, ponieważ jego stan nigdy się nie zmienia, ale przeniesienie tych typowych akcji do metod tego kontenera znacznie poprawia czytelność tam, gdzie jest on używany (kontekst jest ustawiany tylko raz, podobnie jak menedżery kontekstu Pythona) i zmniejsza duplikację, jeśli wykonuje się wiele wywołań metod obiektu.
Izkata,
3
+1 Za jasne powiedzenie, że zmienne składowe nie są zmiennymi globalnymi. Wiele osób uważa, że ​​są.
Tulains Córdova
34

Posiadanie wielu parametrów jest uważane za niepożądane, ale przekształcenie ich w pola lub zmienne globalne jest znacznie gorsze, ponieważ nie rozwiązuje rzeczywistego problemu, ale wprowadza nowe problemy.

Posiadanie wielu parametrów nie jest samo w sobie problemem, ale jest objawem, że możesz mieć problem. Rozważ tę metodę:

Graphics.PaintRectangle(left, top, length, height, red, green, blue, transparency);

Posiadanie 7 parametrów jest wyraźnym znakiem ostrzegawczym. Podstawowym problemem jest to, że parametry te nie są niezależne, ale należą do grup. lefti topsą ze sobą połączone za Position-structure, lengtha heightjako Sizestrukturę, a red, bluea greenjako Colorstrukturę. A może Colorprzejrzystość należy do Brushstruktury? Być może Positioni Sizenależy do siebie w Rectanglestrukturze, w którym to przypadku możemy nawet rozważyć zamianę Paintmetody na Rectangleobiekt? Możemy więc skończyć z:

Rectangle.Paint(brush);

Misja zakończona sukcesem! Ale ważne jest to, że faktycznie poprawiliśmy ogólny projekt, a konsekwencją tego jest zmniejszenie liczby parametrów . Jeśli po prostu zmniejszymy liczbę parametrów bez rozwiązania podstawowych problemów, możemy zrobić coś takiego:

Graphics.left = something;
Graphics.top = something;
Graphics.length = something;
...etc
Graphics.PaintRectangle();

Tutaj osiągnęliśmy taką samą redukcję liczby parametrów, ale w rzeczywistości pogorszyliśmy projekt .

Konkluzja: W przypadku wszelkich porad programowych i praktycznych zasad bardzo ważne jest zrozumienie leżącego u ich podstaw rozumowania.

JacquesB
źródło
4
+1 miła, konstruktywna, zrozumiała, nie teoretyczna odpowiedź.
AnoE
1
Nie wspominając już o tym, do diabła, jaki jest twój „kwadrat”, mając zarówno atrybut długości, jak i wysokości. :)
Wildcard
1
+1 za potwierdzenie, że oczywisty trzeci sposób sugerowany przez niektóre odpowiedzi (tj. Wiele przypisań do jakiejś struktury / obiektu przed wywołaniem funkcji) nie jest lepszy.
benxyzzy
@Wildcard: Dzięki, zmieniłem go na „prostokąt”, aby uniknąć pomyłki!
JacquesB
7

czy warto używać zmiennych globalnych w celu zmniejszenia liczby parametrów funkcji, czy nie?

Nie

Przeczytałem pierwsze rozdziały tej książki

Czy przeczytałeś resztę książki?

Globalny jest tylko ukrytym parametrem. Powodują inny ból. Ale to wciąż ból. Przestań myśleć o sposobach obejścia tej zasady. Zastanów się, jak tego przestrzegać.

Co to jest parametr?

To rzeczy. W ładnie oznakowanym pudełku. Dlaczego to ma znaczenie, ile masz pudełek, kiedy możesz włożyć w to wszystko?

Jest to koszt wysyłki i przeładunku.

Move(1, 2, 3, 4)

Powiedz mi, że możesz to przeczytać. Dalej, spróbuj.

Move(PointA, PointB)

Dlatego.

Ta sztuczka nazywana jest obiektem wprowadzania parametru .

I tak, to tylko sztuczka, jeśli wszystko, co robisz, to zliczanie parametrów. To, co powinieneś liczyć, to POMYSŁY! Abstrakcje! Ile każesz mi od razu myśleć? Nie komplikuj.

Teraz jest to ta sama liczba:

Move(xyx, y)

OW! To okropne! Co tu poszło nie tak?

Nie wystarczy ograniczyć liczbę pomysłów. Muszą to być jasne pomysły. Czym do cholery jest xyx?

To wciąż jest słabe. Jaki jest lepszy sposób myślenia o tym?

Funkcje powinny być małe. Nie mniejszy niż to.

Wujek Bob

Move(PointB)

Po co sprawić, by ta funkcja działała więcej, niż jest w rzeczywistości potrzebna? Zasada pojedynczej odpowiedzialności nie dotyczy tylko zajęć. Poważnie, warto zmienić całą architekturę, aby powstrzymać jedną funkcję przed przeobrażeniem się w przeciążony koszmar z 10 czasami powiązanymi parametrami, z których niektóre nie mogą być używane z innymi.

Widziałem kod, w którym najczęściej występującą liczbą linii w funkcji było 1. Poważnie. Nie mówię, że musisz tak pisać, ale szepcze, nie mów mi, że globalny jest JEDYNYM sposobem na przestrzeganie tej zasady. Przestań próbować wyjść z refaktoryzacji tej funkcji poprawnie. Wiesz, że możesz. Może się on podzielić na kilka funkcji. Może faktycznie zmienić się w kilka obiektów. Do diabła, możesz nawet rozbić jego część na zupełnie inną aplikację.

Książka nie mówi ci, byś liczył swoje parametry. Mówi ci, abyś zwracał uwagę na ból, który powodujesz. Wszystko, co naprawia ból, rozwiązuje problem. Bądź świadomy, kiedy po prostu zamieniasz jeden ból na inny.

candied_orange
źródło
3
„Czytałeś resztę książki?” Odpowiedzi na twoje pytanie udzielono w pierwszych 8 słowach mojego postu ...
OiciTrap
Całkowicie się zgadzam - chodzi o to, aby rozłożyć problem na małe kawałki. Obiekty mogą naprawdę pomóc zorganizować te elementy i pogrupować je, pozwalają też na przekazanie pojedynczej jednostki konceptualnej jako parametru, a nie grupy niepowiązanych elementów. Dostaję mdłości, gdy widzę metodę z więcej niż 3 parametrami. 5 jest wskazówką, że mój projekt poszedł na marne i potrzebuję kolejnej rundy refaktoryzacji. Najlepszym sposobem, w jaki znalazłem rozwiązanie problemów projektowych, takich jak zliczanie parametrów, jest po prostu przekształcenie rzeczy w mniejsze, prostsze jednostki (klasy / metody).
Bill K
2
Ton tej odpowiedzi można poprawić. Czyta się to jako bardzo gwałtowne i ostre. Na przykład: „Powiedz mi, że możesz to przeczytać. Dalej, spróbuj”. wydaje się bardzo agresywny i można go przepisać jako „Z dwóch wywołań funkcji powyżej / poniżej, który z nich jest łatwiejszy do odczytania?” Powinieneś spróbować przejść przez punkt bez agresji. PO próbuje się tylko nauczyć.
Kyle A
Nie zapominaj, że OP stara się również nie zasnąć.
candied_orange
4

Nigdy nie użyłbym zmiennych globalnych do zmniejszenia parametrów. Powodem jest to, że zmienne globalne mogą być zmieniane przez dowolną funkcję / komendę, co powoduje, że dane wejściowe funkcji są niewiarygodne i podatne na wartości, które są poza zakresem tego, co funkcja może obsłużyć. Co jeśli zmienna została zmieniona podczas wykonywania funkcji, a połowa funkcji miała inne wartości niż druga połowa?

Z drugiej strony przekazywanie parametrów ogranicza zasięg zmiennej tylko do jej własnej funkcji, tak że tylko funkcja może modyfikować parametr po jego wywołaniu.

Jeśli zamiast parametru należy przekazać zmienne globalne, lepiej przeprojektować kod.

Tylko moje dwa centy.

Dimos
źródło
„Nigdy nie używałbym zmiennych globalnych do zmniejszania parametrów” całkowicie się zgadzam. Tworzy niepotrzebne sprzężenie.
bytedev
2

W tej sprawie jestem z wujkiem Bobem i zgadzam się, że należy unikać więcej niż 3 parametrów (bardzo rzadko używam więcej niż 3 parametrów w funkcji). Posiadanie wielu parametrów na jednej funkcji stwarza większy problem z konserwacją i prawdopodobnie jest to zapach, że twoja funkcja wykonuje zbyt wiele / ma zbyt wiele obowiązków.

Jeśli używasz więcej niż 3 w metodzie w języku OO, powinieneś rozważyć, czy parametry nie są ze sobą w jakiś sposób powiązane i dlatego naprawdę powinieneś przekazać obiekt?

Ponadto, jeśli utworzysz więcej (mniejszych) funkcji, zauważysz również, że funkcje mają zwykle 3 parametry lub mniej. Funkcja / metoda wyodrębniania jest twoim przyjacielem :-).

Nie używaj zmiennych globalnych jako sposobu na uzyskanie większej liczby parametrów! To zamienia jedną złą praktykę na jeszcze gorszą!

bytedev
źródło
1

Prawidłową alternatywą dla wielu parametrów funkcji jest wprowadzenie obiektu parametru . Jest to przydatne, jeśli masz metodę złożoną , która przekazuje (prawie) wszystkie jej parametry do wielu innych metod.

W prostych przypadkach jest to prosty DTO, który ma jedynie stare parametry jako właściwości.

Timothy Truckle
źródło
1

Używanie zmiennych globalnych zawsze wydaje się łatwym sposobem na kodowanie (szczególnie w małym programie), ale utrudnia rozszerzanie kodu.

Tak, można zmniejszyć liczbę parametrów w funkcji, używając tablicy do powiązania parametrów w jednym obiekcie.

function <functionname>(var1,var2,var3,var4.....var(n)){}

Powyższa funkcja zostanie edytowana i zmieniona na [przy użyciu tablicy asocjacyjnej] -

data=array(var1->var1,
           var2->var2
           var3->var3..
           .....
           ); // data is an associative array

function <functionname>(data)

Zgadzam się z odpowiedzią Roberta Christow-Johnsona : możesz nawet użyć struktury, aby powiązać dane w jednym bycie.

Narender Parmar
źródło
1

Biorąc przykład z PHP 4, spójrz na podpis funkcji dla mktime():

  • int mktime ([ int $hour = date("H") [, int $minute = date("i") [, int $second = date("s") [, int $month = date("n") [, int $day = date("j") [, int $year = date("Y") [, int $is_dst = -1 ]]]]]]] )

Nie uważasz tego za mylące? Funkcja nazywa się „ustaw czas”, ale wymaga parametrów dnia, miesiąca i roku, a także trzech parametrów czasu. Jak łatwo jest pamiętać, w jakiej kolejności się znajdują? Co jeśli zobaczysz mktime(1, 2, 3, 4, 5, 2246);? Czy możesz to zrozumieć bez konieczności odwoływania się do czegokolwiek innego? Czy 2246interpretowany jest jako czas 24-godzinny „22:46”? Co oznaczają inne parametry? Byłoby lepiej jako obiekt.

Przechodząc do PHP 5, istnieje teraz obiekt DateTime. Wśród jego metod są dwie nazywane setDate()i setTime(). Ich podpisy są następujące:

  • public DateTime setDate ( int $year , int $month , int $day )
  • public DateTime setTime ( int $hour , int $minute [, int $second = 0 ] )

Nadal musisz pamiętać, że kolejność parametrów zmienia się od największej do najmniejszej, ale to duża poprawa. Zauważ, że nie ma jednej metody, która pozwala ustawić wszystkie sześć parametrów jednocześnie. Aby to zrobić, musisz wykonać dwa osobne połączenia.

To, o czym mówi wujek Bob, to unikanie płaskiej struktury. Powiązane parametry powinny być zgrupowane razem w obiekt, a jeśli masz więcej niż trzy parametry, bardzo prawdopodobne jest, że masz tam pseudo obiekt, co daje ci możliwość stworzenia odpowiedniego obiektu dla większej separacji. Chociaż PHP nie ma oddzielnej Datei Timeklasy, można uznać, że DateTimetak naprawdę zawiera Dateobiekt i Timeobiekt.

Możesz mieć następującą strukturę:

<?php
$my_date = new Date;
$my_date->setDay(5);
$my_date->setMonth(4);
$my_date->setYear(2246);

$my_time = new Time;
$my_time->setHour(1);
$my_time->setMinute(2);
$my_time->setSecond(3);

$my_date_time = new DateTime;
$my_date_time->setTime($my_time);
$my_date_time->setDate($my_date);
?>

Czy za każdym razem należy ustawić dwa lub trzy parametry? Jeśli chcesz zmienić tylko godzinę lub dzień, teraz możesz to łatwo zrobić. Tak, obiekt musi zostać sprawdzony, aby upewnić się, że każdy parametr działa z innymi, ale tak było wcześniej.

Najważniejsze jest to, czy łatwiej to zrozumieć, a zatem utrzymać? Blok kodu na dole jest większy niż pojedyncza mktime()funkcja, ale twierdzę, że jest to o wiele łatwiejsze do zrozumienia; nawet osoba niebędąca programistą nie miałaby większych problemów z ustaleniem, co robi. Celem nie zawsze jest krótszy kod lub sprytniejszy kod, ale łatwiejszy do utrzymania kod.

Och, i nie używaj globałów!

CJ Dennis
źródło
1

Wiele dobrych odpowiedzi tutaj, ale większość nie odnosi się do tego. Dlaczego te podstawowe zasady? Chodzi o zakres, chodzi o zależności i dotyczy odpowiedniego modelowania.

Globalizacja argumentów jest gorsza, ponieważ wygląda tylko tak, jakbyś ją uprościł, ale w rzeczywistości ukryłeś tylko złożoność. Nie widzisz go już w prototypie, ale wciąż musisz być tego świadomy (co jest trudne, ponieważ nie ma go więcej), a obejście logiki funkcji nie pomoże ci, ponieważ może bądź inna ukryta logika, która przeszkadza za twoimi plecami. Twój zasięg rozszedł się wszędzie i wprowadziłeś zależność od wszystkiego, ponieważ cokolwiek może teraz zepsuć twoją zmienną. Niedobrze.

Najważniejszą rzeczą do utrzymania dla funkcji jest to, że możesz zrozumieć, co ona robi, patrząc na prototyp i wywołanie. Więc nazwa powinna być jasna i jednoznaczna. Ale im więcej argumentów, tym trudniej będzie zrozumieć, co robi. Poszerza zakres w twojej głowie, dzieje się zbyt wiele rzeczy, dlatego chcesz ograniczyć liczbę. Ważne jest, z jakimi argumentami masz do czynienia, niektóre są gorsze od innych. Dodatkowa opcjonalna wartość logiczna, która pozwala na przetwarzanie bez rozróżniania wielkości liter, nie sprawia, że ​​funkcja jest trudniejsza do zrozumienia, więc nie chcesz robić o tym wielkiej sprawy. Na marginesie, wyliczenia dają lepsze argumenty niż booleany, ponieważ znaczenie wyliczenia jest oczywiste w wywołaniu.

Typowy problem nie polega na tym, że piszesz nową funkcję z ogromną liczbą argumentów, zaczniesz od kilku, gdy nie zdasz sobie jeszcze sprawy z tego, jak skomplikowany jest naprawdę rozwiązany problem. W miarę rozwoju programu listy argumentów stopniowo się wydłużają. Gdy model zapadnie Ci w pamięć, chcesz go zachować, ponieważ jest to bezpieczne odniesienie, które znasz. Ale z perspektywy czasu model może nie być taki świetny. Przegapiłeś krok lub logikę i nie rozpoznałeś jednego lub dwóch bytów. „OK ... mógłbym zacząć od nowa i spędzić dzień lub dwa na refaktoryzacji kodu lub… mógłbym dodać ten argument, aby w końcu mógł zrobić to dobrze i zrobić to. Na razie. Dla tego scenariusza , Aby usunąć ten błąd z mojego talerza, abym mógł przenieść notatkę.

Im częściej korzystasz z drugiego rozwiązania, tym droższa będzie dalsza konserwacja i tym trudniejszy i nieatrakcyjny stanie się reaktor.

Nie ma rozwiązania dla płyty kotłowej do zmniejszenia liczby argumentów w istniejącej funkcji. Samo grupowanie ich w związki naprawdę nie ułatwia rzeczy, to po prostu inny sposób wcierania złożoności pod dywan. Właściwe wykonanie tego zadania polega na ponownym spojrzeniu na cały stos wywołań i rozpoznaniu tego, czego brakuje lub co zostało zrobione źle.

Martin Maat
źródło
0

Kilka razy stwierdziłem, że grupowanie wielu przesłanych razem parametrów poprawiło sytuację.

  • Zmusza cię do nadania dobrego imienia temu zestawieniu pojęć używanych razem. Jeśli użyjesz tych parametrów razem, może to oznaczać, że mają one związek (lub że w ogóle nie powinieneś ich używać).

  • Kiedyś z obiektem zwykle stwierdzam, że można przesunąć pewną funkcjonalność tego pozornie głupiego obiektu. Zwykle jest łatwy do przetestowania, a dzięki dużej kohezji i niskiemu sprzężeniu wszystko jest jeszcze lepsze.

  • Następnym razem, gdy muszę dodać nowy parametr, mam fajne miejsce na jego włączenie bez zmiany sygnatury wielu metod.

Może to nie działać w 100% razy, ale zadaj sobie pytanie, czy ta lista parametrów powinna być zgrupowana w obiekcie. I proszę. Nie używaj nietypowych klas, takich jak Tuple, aby uniknąć tworzenia obiektu. Korzystasz z programowania obiektowego, nie przejmuj się tworzeniem kolejnych obiektów, jeśli ich potrzebujesz.

Borjab
źródło
0

Z całym szacunkiem jestem pewien, że całkowicie przegapiłeś sens posiadania małej liczby parametrów w funkcji.

Chodzi o to, że mózg może przechowywać jednocześnie tyle „aktywnych informacji”, a jeśli masz n parametrów w funkcji, masz n więcej fragmentów „aktywnych informacji”, które muszą być w twoim mózgu, aby łatwo i dokładnie zrozumieć, co robi kawałek kodu (Steve McConnell, w Code Complete (znacznie lepsza książka, IMO), mówi coś podobnego o 7 zmiennych w ciele metody: rzadko do tego dochodzimy, ale już więcej i tracisz umiejętność trzymania wszystkiego prosto w głowie).

Istotą niskiej liczby zmiennych jest utrzymanie małych wymagań poznawczych związanych z pracą z tym kodem, abyś mógł nad nim pracować (lub czytać) bardziej efektywnie. Boczną przyczyną tego jest fakt, że dobrze ustrukturyzowany kod będzie miał tendencję do posiadania coraz mniej parametrów (np. Źle ułożony kod ma tendencję do grupowania wielu rzeczy w bałagan).

Przekazując obiekty zamiast wartości, być może zyskujesz poziom abstrakcji dla twojego mózgu, ponieważ teraz musi zrozumieć , że tak, mam tutaj SearchContext, zamiast myśleć o 15 właściwościach, które mogą znajdować się w tym kontekście wyszukiwania.

Próbując użyć zmiennych globalnych, całkowicie poszedłeś w złym kierunku. Teraz nie tylko nie rozwiązałeś problemów związanych z posiadaniem zbyt wielu parametrów dla funkcji, ale podjąłeś ten problem i rzuciłeś go na znacznie, o wiele lepszy problem, który musisz teraz mieć w głowie!

Teraz zamiast pracować tylko na poziomie funkcji, musisz również wziąć pod uwagę globalny zakres swojego projektu (gap, jakie to okropne! Wzdrygam się ...). Nie masz nawet wszystkich swoich informacji przed sobą w funkcji (cholera, jak nazywa się ta zmienna globalna?) (Mam nadzieję, że nie zostało to zmienione przez coś innego, odkąd wywołałem tę funkcję).

Zmienne o zasięgu globalnym są jedną z najgorszych rzeczy do zobaczenia w projekcie (dużym lub małym). Oznaczają niepełnosprawność do właściwego zarządzania zakresem, co jest bardzo podstawową umiejętnością programowania. One. Są Zło.

Usuwając parametry z funkcji i umieszczając je w globach, strzeliłeś sobie w podłogę (lub nogę lub twarz). I Boże, nie pozwól, żebyś kiedykolwiek zdecydował, że hej, mogę ponownie użyć tego globalnego do czegoś innego ... mój umysł drży na tę myśl.

Ideałem jest łatwość zarządzania, a zmienne globalne NIE będą tego robić. Chciałbym powiedzieć, że są jedną z najgorszych rzeczy, które możesz zrobić, aby pójść w przeciwnym kierunku.

Jleach
źródło
-1

Znalazłem wysoce skuteczne podejście (w JavaScript), aby zminimalizować tarcie między interfejsami: Użyj jednolitego interfejsu dla wszystkich modułów , w szczególności: funkcji pojedynczych parametrów.

Gdy potrzebujesz wielu parametrów: użyj jednego obiektu / skrótu lub tablicy.

Bądź ze mną, obiecuję, że nie trolluję ...

Zanim powiesz „jaki jest pożytek z pojedynczego parametru?” Lub „Czy istnieje różnica między funkcjami 1 Array a wieloma argumentami?”

No tak. Być może jest subtelny wizualnie, ale różnica jest wielorakie - tutaj badam wiele korzyści

Najwyraźniej niektórzy ppl uważają, że 3 to właściwa liczba argumentów. Niektórzy myślą, że to 2. Cóż, to wciąż nasuwa pytanie: „który parametr wchodzi w arg [0]?”. Zamiast wybierać opcję, która ogranicza interfejs z bardziej sztywną deklaracją.

Chyba opowiadam się za bardziej radykalnym stanowiskiem: nie polegaj na argumentach pozycyjnych. Po prostu czuję, że jest delikatny i prowadzi do sporów o pozycję tych przeklętych argumentów. Pomiń to i przejdź od razu do nieuchronnej walki o nazwy funkcji i zmiennych. 😉

Poważnie jednak, po ustaleniu nazw, mam nadzieję, że skończysz z kodem podobnym do poniższego, który jest nieco samodokumentujący, niewrażliwy na położenie i pozwala na obsługę przyszłych zmian parametrów wewnątrz funkcji:

function sendMessage({toUser, fromUser, subject, body}) { }

// And call the method like so:
sendMessage({toUser: this.parentUser, fromUser: this.currentUser, subject: ‘Example Alert’})

Dan Levy
źródło
6
Udawanie nazwanych argumentów tak naprawdę nie przekazuje tylko jednego argumentu.
JDługosz
Dlaczego to „udawanie”, jeśli osiągnąłem wyznaczony cel? Nadaję wyższy priorytet nazwanym argumentom. Ponieważ argumenty pozycyjne nie są oczywiste dla wywoływania kodu, a przy # nazwanych funkcjach programista musi zapamiętać, nie jest pomocne zapamiętanie, które parametry są gdzie, a które opcjonalne. ... W końcu będziesz chciał dodać wymagany parametr po opcjach, powodzenia w dokumentowaniu i ulepszaniu tego domu kart.
Dan Levy
2
Nazwane parametry są również sztuczką wzmacniającą - ludzie przywiązują większą wagę do kolekcji słów.
Dan Levy