Czy parametry opcjonalne są pomocne czy utrudniają utrzymanie aplikacji? [Zamknięte]

15

Jak podano w tytule, czy parametry opcjonalne, takie jak te używane w języku C #, są pomocne, czy stanowią przeszkodę w utrzymaniu aplikacji i należy ich unikać, ponieważ mogą utrudnić zrozumienie kodu?

rjzii
źródło
3
Oświadczenie: każda funkcja językowa w niewłaściwych rękach może być nadużywana. Jeśli język implementuje to w sprytny sposób, a ta funkcja języka nie nakłada się zbytnio z istniejącą funkcją języka w tępy sposób, to jest w porządku, w rzeczywistości całkiem przydatna. Python ma kilka schludnych parametrów pakowania / rozpakowywania i inne „sztuczki” parametrów (sztuczki w dobrym, a nie perlowym sensie).
Job
Spróbuj napisać aplikację w języku C #, która łączy się z programem Excel bez użycia opcjonalnych parametrów. To powinno odpowiedzieć na twoje pytanie ponad wszelkie uzasadnione wątpliwości.
Dunk

Odpowiedzi:

22

Opcjonalne parametry, z mojego doświadczenia, były dobrą rzeczą. Nigdy nie uważałem ich za mylące (przynajmniej nie bardziej mylące niż rzeczywista funkcja), ponieważ zawsze mogę uzyskać wartości domyślne i wiedzieć, co się nazywa.

Jednym z nich jest to, że muszę dodać kolejny parametr do funkcji, która jest już w powszechnym użyciu lub przynajmniej w interfejsie publicznym. Bez nich musiałbym powtórzyć oryginalną funkcję, aby wywołać funkcję, która ma inny argument, i która może się naprawdę zestarzeć, jeśli skończę dodawać argumenty więcej niż raz.

David Thornley
źródło
1
+1 I to jest cenne w przypadku przeciążonych metod, które dodają argument, np. new Circle(size, color, filled, ellipseProportions)Gdzie sizei colorsą wymagane, a reszta jest domyślna.
Michael K
15

Ogólnie rzecz biorąc, jeśli często potrzebujesz wielu / opcjonalnych parametrów, twoje funkcje robią za dużo i powinny zostać zepsute. Prawdopodobnie łamiesz SRP (zasada pojedynczej odpowiedzialności).

Poszukaj parametrów, które można grupować, np. (Xiy stają się punktem).

Czy te opcjonalne parametry flagi mają wartość domyślną? Jeśli używasz flag, funkcja powinna zostać podzielona.

Nie oznacza to, że nigdy nie powinieneś mieć parametrów opcjonalnych, ale ogólnie więcej niż jeden lub dwa parametry sugerują zapach kodu.

Może to być również wskazówka, że ​​funkcja powinna być klasą, z opcjonalnymi parametrami zmienionymi na właściwości i wymaganymi parametrami części konstruktora.

CaffGeek
źródło
1
+1 za ostrożność. Każda funkcja, bez względu na to, jak dobra, może zostać wykorzystana.
Michael K
3
To świetna rada do tworzenia nadeksperymentowanego kodu ravioli, w którym użytkownicy Twojego API muszą korzystać z co najmniej 6 klas i 15 funkcji, aby nawet najprostsza rzecz się wydarzyła.
dsimcha
1
@dsimcha, skąd masz to, co napisałem? Łał. Proszę wytłumacz? Byłoby to równie złe zaprojektowanie posiadania „superfunkcji”, którą otrzymujesz, gdy masz wiele opcjonalnych parametrów. Przeczytaj o zasadach projektowania SOLID i pisaniu testowalnego kodu. Najlepiej przy użyciu TDD. Potem wróć i spróbuj mi wyjaśnić, że obniżanie parametrów funkcji jest złą rzeczą.
CaffGeek,
1
Testowalny kod jest fajny, ale tak samo jest z czystym, użytecznym API, który nie jest zbyt drobnoziarnisty ani gadatliwy i nie wtrąca klas w sytuacje, w których funkcja jest właściwą abstrakcją. Wierzę w zasadę pojedynczej odpowiedzialności, której obowiązki określono na wysokim poziomie abstrakcji. Jeśli obowiązki są zdefiniowane na zbyt niskim poziomie, poszczególne jednostki stają się nadmiernie uproszczone, tak że ich interakcje są nadmiernie złożone.
dsimcha
1
@dsimcha, brakuje ci sensu. Poszczególne jednostki powinny pozostać pojedynczymi jednostkami i nie powinny być łączone w jedną funkcję. Nie oznacza to również, że wszystkie są funkcjami publicznie dostępnymi. Twój interfejs API jest bramą do kodu i powinien być czysty i zwięzły. Funkcja z kilkoma opcjonalnymi parametrami nie jest ani czysta, ani zwięzła. Jednak przeciążenie jednej funkcji parametrami logicznymi jest znacznie wyraźniejsze. Na przykład istnieją funkcje w wielu interfejsach API, w których dwa parmy są opcjonalne, ale jedno lub drugie jest wymagane. Co jest jasne, gdy oba są oznaczone jako opcjonalne?
CaffGeek,
4

Parametry opcjonalne są w porządku

Zazwyczaj uzasadnia się to tym, że: a) wiesz, że masz wiele możliwych argumentów dla swojej metody, ale nie chcesz przeciążać z obawy przed zaśmieceniem interfejsu API, lub b) gdy nie znasz wszystkich możliwych argumentów, ale nie chcę zmuszać użytkownika do zapewnienia tablicy. W każdym przypadku na ratunek przychodzą opcjonalne parametry w zgrabny i elegancki sposób.

Oto kilka przykładów:

1. Chcesz uniknąć przeciążenia i nie chcesz określać tablicy

Spójrz na printf () z C, Perl, Java itp. To świetny przykład potęgi parametrów opcjonalnych.

Na przykład:

printf("I want %d %s %s",1,"chocolate","biccies");

printf("I want %d banana",1);

Bez przeładowania, bez tablic, proste i intuicyjne (po opanowaniu standardowych kodów formatu ciągów). Niektóre IDE powiedzą ci nawet, czy łańcuch formatu nie pasuje do opcjonalnych parametrów.

2. Chcesz zezwolić na użycie ustawień domyślnych i ukryć je przed użytkownikiem metody

sendEmail („[email protected]”);

Metoda sendEmail wykrywa brak różnych istotnych wartości i wypełnia je przy użyciu zdefiniowanych wartości domyślnych (podmiot, treść, DW, UDW itp.). Interfejs API jest czysty, ale elastyczny.

Uwaga na zbyt wiele parametrów

Jednak, jak stwierdzili inni, posiadanie zbyt wielu parametrów obowiązkowych w stosunku do metody wskazuje, że prawdopodobnie masz coś złego w swoim projekcie. Jest to szczególnie prawdziwe, jeśli mają ten sam typ, ponieważ mogą zostać przypadkowo przełączone przez programistę, co prowadzi do dziwnych wyników w czasie wykonywania:

String myMethod(String x, String y, String z, String a, int b, String c, int d) {}

jest idealnym kandydatem do utworzenia refaktoryzacji obiektu parametrów parametru

String myMethod(ParameterObject po) {}

class ParameterObject {
  // Left as public for clarity
  public String x;
  public String y;
  ... etc

}

To z kolei może prowadzić do lepszego projektu opartego na wzorcu fabrycznym z dostarczoną specyfikacją jako obiektem parametru.

Gary Rowe
źródło
1
funkcje formatowania ciągów, takie jak printf, są wyjątkiem od reguły, można argumentować, że chociaż używają nieograniczonej listy parametrów opcjonalnych, bardziej przypomina argument jako tablicę niż parametry opcjonalne, pomimo tego, jak jest implementowany.
CaffGeek
@Chad Dostosowałem swoją odpowiedź, aby lepiej rozróżniać parametry opcjonalne i kiedy przechodzą one w zapach kodu (jak wspomniałeś w odpowiedzi).
Gary Rowe
@ Gary Rowe, w większości przypadków zbyt wiele opcjonalnych parametrów jest złych.
CaffGeek
@Chad Zgadzam się, ale większość języków nie pozwala na określenie limitu opcjonalnych argumentów, więc jest to podejście typu wszystko albo nic. Jesteś zmuszony pozostawić to swojej metodzie egzekwowania i oczywiście, jeśli twoja metoda ma do czynienia z 500 zmiennymi, to na pewno będzie trzeba ją zrefaktoryzować.
Gary Rowe
@Gary Rowe, co masz na myśli mówiąc „większość języków nie zapewnia sposobu na ograniczenie liczby opcjonalnych argumentów”? W większości języków oznacza się je jako takie lub nie podaje się ich wartości podczas wywoływania funkcji, ale nagłówek funkcji nadal ma zdefiniowane parametry. To prawda, że ​​w niektórych językach możesz dodać tyle parametrów, ile chcesz po wypełnieniu zdefiniowanych, ale nie sądzę, że o takich parametrach opcjonalnych mówimy tutaj. (oprócz wyjątku formatu łańcucha)
CaffGeek
2

Jednym z problemów z domyślnymi parametrami w C # (myślę, że void DoSomething (int x = 1)) jest to, że są one stałe. Oznacza to, że jeśli zmienisz ustawienie domyślne, będziesz musiał ponownie skompilować wszystkich odbiorców tego wywołania metody. Chociaż jest to dość łatwe, zdarzają się sytuacje, w których jest to niebezpieczne.

Po-ta-toe
źródło
1

To zależy od tego, co robi twój kod. Jeśli istnieją rozsądne wartości domyślne, powinieneś użyć parametrów opcjonalnych, ale jeśli nie ma żadnych sensownych wartości domyślnych, dodanie parametrów opcjonalnych sprawi, że kod będzie bardziej skomplikowany. W wielu przypadkach opcjonalne parametry są dobrym sposobem na ominięcie kontroli zerowych i wycięcie logiki rozgałęziania. JavaScript nie ma parametrów opcjonalnych, ale istnieje sposób na ich emulację za pomocą || (logiczne lub) i używam go cały czas podczas robienia rzeczy związanych z bazą danych, ponieważ jeśli użytkownik nie poda żadnej wartości, wówczas podstawiam własne wartości za pomocą || co oszczędza mi kłopotów z pisaniem całego zestawu instrukcji if if.

davidk01
źródło
1

Parametry opcjonalne to świetny sposób, aby proste rzeczy były proste, a skomplikowane rzeczy możliwe jednocześnie. Jeśli istnieje wyraźna rozsądna wartość domyślna, której większość użytkowników będzie chciała, przynajmniej w szybkich i brudnych przypadkach użycia, nie powinni oni musieć pisać schematu, aby ręcznie określać to za każdym razem, gdy wywołują twoją funkcję. Z drugiej strony, jeśli ludzie mogą mieć dobry powód, aby chcieć to zmienić, należy to ujawnić.

Korzystanie z klasy jest IMHO okropnym rozwiązaniem, ponieważ jest pełne, nieefektywne i niezgodne z typowym modelem mentalnym tego, co robi klasa. Funkcja jest idealną abstrakcją czasownika, tzn. Robienia czegoś i powrotu. Klasa jest właściwą abstrakcją dla rzeczownika, tzn. Czymś, co ma stan i można nim manipulować na kilka sposobów. Jeśli ten pierwszy powinien być modelem mentalnym użytkownika API, nie rób z niego klasy.

dsimcha
źródło
1

Problem z opcjonalnymi argumentami polega na tym, że ludzie mają tendencję do wkładania coraz większej liczby (i więcej) argumentów do funkcji zamiast wydobywania odpowiedniego kodu do nowej funkcji. To jest doprowadzone do skrajności w php . Na przykład:

bool array_multisort ( array &$arr [, mixed $arg = SORT_ASC
                      [, mixed $arg = SORT_REGULAR [, mixed $... ]]] )
Martin Wickman
źródło
1

Parametry opcjonalne to w zasadzie inny sposób przeciążania funkcji. To w zasadzie sprowadza się do: „czy przeciążenie funkcji jest złe”?

Pieter B.
źródło
1

Początkowo podobała mi się ta funkcja w Pythonie i wykorzystałem ją do „rozszerzenia” już używanych metod. I wyglądało to ładnie i łatwo, ale wkrótce się ugryzło; ponieważ kiedy dodałem parametr opcjonalny, modyfikowało to zachowanie istniejącej metody, na której polegał stary klient, w sposób, który nie został przechwycony przez istniejące przypadki testów jednostkowych. Zasadniczo robi to łamanie otwartej zasady zamkniętej; kod jest otwarty do rozszerzenia, ale zamknięty do modyfikacji. Uważam więc, że użycie tej funkcji do modyfikacji istniejącego kodu nie jest dobrym pomysłem; ale w porządku, jeśli jest używany od samego początku

Alex Punnen
źródło
0

Wydaje mi się, że lepiej byłoby przeciążić funkcję innymi podpisami (tj. Parametrami) niż użyć parametrów opcjonalnych.

HardCode
źródło
Dlaczego? Myślę, że jest to bardziej przejrzyste, jeśli można połączyć kilka przeciążonych metod w jedną metodę przy użyciu domyślnych parametrów, jeśli wszystkie metody mają tę samą podstawową funkcjonalność
Amit Wadhwa
Możesz tak myśleć. Nie jestem zdania, że ​​Microsoft robi wszystko we właściwy sposób, ale jeśli byłeś dokładny, to nigdy nie widziałbym przeciążeń podczas korzystania z frameworku .NET, tylko jedna wielka sygnatura funkcji - jak w starym VB6.
HardCode