Dlaczego kodowanie nazw argumentów w nazwach funkcji nie jest częstsze? [Zamknięte]


47

W Clean Code autor podaje przykład

assertExpectedEqualsActual(expected, actual)

vs

assertEquals(expected, actual)

z tym pierwszym twierdzono, że jest bardziej przejrzysty, ponieważ eliminuje potrzebę pamiętania, gdzie idą argumenty i potencjalne niewłaściwe użycie z tego wynikające. Jednak nigdy nie widziałem przykładu poprzedniego schematu nazewnictwa w żadnym kodzie i cały czas go widzę. Dlaczego koderzy nie przyjmują tego pierwszego, jeśli jest, jak twierdzi autor, jaśniejszy od drugiego?


9
Myślę, że to świetne pytanie do dyskusji. Ale nie jest to coś, na co można odpowiedzieć obiektywną odpowiedzią. To pytanie może zostać zamknięte jako oparte na opiniach.
Euforyczny

54
Wiele osób sprzeciwiałoby się pierwszemu schematowi nazewnictwa, ponieważ jest on nadmiernie gadatliwy , daleko poza punktem, w którym poprawiłby przejrzystość. Szczególnie w przypadku assertEquals()tej metody stosuje się setki razy w bazie kodu, więc można oczekiwać, że czytelnicy raz zapoznają się z konwencją. Różne frameworki mają różne konwencje (np. (actual, expected) or an agnostic (Lewy, prawy) `), ale z mojego doświadczenia wynika, że ​​co najwyżej niewielkie źródło zamieszania.
amon

5
Ponieważ zysk jest tak mały, w porównaniu do korzyści, że każdy rozsądny człowiek prawdopodobnie odejdzie. Jeśli chcesz bardziej płynnego podejścia, powinieneś spróbować assert(a).toEqual(b)(nawet jeśli IMO wciąż jest niepotrzebnie gadatliwy), gdzie możesz połączyć kilka powiązanych twierdzeń.
Adriano Repetti

18
Skąd wiemy, że rzeczywiste i oczekiwane są wartości? Z pewnością tak powinno być assertExpectedValueEqualsActualValue? Ale poczekaj, jak pamiętamy, czy używa ==lub .equalsczy Object.equals? Powinno być assertExpectedValueEqualsMethodReturnsTrueWithActualValueParameter?
user253751,

6
Biorąc pod uwagę, że w przypadku tej konkretnej metody kolejność dwóch argumentów nie ma znaczenia, wydaje się złym przykładem wybranie korzyści z tego schematu nazewnictwa.
Steven Rands

Odpowiedzi:


66

Ponieważ bardziej jest pisać, a więcej czytać

Najprostszym powodem jest to, że ludzie lubią pisać mniej, a kodowanie tych informacji oznacza więcej pisania. Czytając go, za każdym razem muszę przeczytać całość, nawet jeśli wiem, jaka powinna być kolejność argumentów. Nawet jeśli nie zna kolejności argumentów ...

Wielu programistów używa IDE

IDE często zapewniają mechanizm przeglądania dokumentacji dla danej metody poprzez najechanie myszką lub za pomocą skrótu klawiaturowego. Z tego powodu nazwy parametrów są zawsze pod ręką.

Kodowanie argumentów wprowadza powielanie i łączenie

Nazwy parametrów powinny już dokumentować, jakie są. Pisząc nazwy w nazwie metody, kopiujemy również te informacje w podpisie metody. Tworzymy również sprzężenie między nazwą metody a parametrami. Powiedz expectedi actualsą mylące dla naszych użytkowników. Przejście z assertEquals(expected, actual)do assertEquals(planned, real)nie wymaga zmiany kodu klienta za pomocą funkcji. Przejście od assertExpectedEqualsActual(expected, actual)do assertPlannedEqualsReal(planned, real)oznacza przełomową zmianę w interfejsie API. Lub nie zmieniamy nazwy metody, która szybko staje się myląca.

Używaj typów zamiast dwuznacznych argumentów

Prawdziwy problem polega na tym, że mamy niejednoznaczne argumenty, które można łatwo przełączać, ponieważ są tego samego typu. Zamiast tego możemy użyć naszego systemu typów i naszego kompilatora do wymuszenia prawidłowej kolejności:

class Expected<T> {
    private T value;
    Expected(T value) { this.value = value; }
    static Expected<T> is(T value) { return new Expected<T>(value); }
}

class Actual<T> {
    private T value;
    Actual(T value) { this.value = value; }
    static Actual<T> is(T value) { return new Actual<T>(value); }
}

static assertEquals(Expected<T> expected, Actual<T> actual) { /* ... */ }

// How it is used
assertEquals(Expected.is(10), Actual.is(x));

Można to następnie wymusić na poziomie kompilatora i zagwarantować, że nie będzie można uzyskać ich wstecz. Podchodząc z innej strony, to właśnie robi biblioteka Hamcrest dla testów.


5
Cóż, jeśli używasz IDE, masz nazwy parametrów w pomocy balonu; jeśli go nie użyjesz, zapamiętanie nazwy funkcji jest równoznaczne z zapamiętaniem argumentów, więc nic nie zostanie uzyskane w żaden sposób.
Peter - Przywróć Monikę

29
Jeśli nie zgadzasz się z assertExpectedEqualsActual„bo to więcej do pisania, a więcej do czytania”, to jak możesz się bronić assertEquals(Expected.is(10), Actual.is(x))?
ruakh

9
@ruakh to nie jest porównywalne. assertExpectedEqualsActualnadal wymaga od programisty dokładnego określenia argumentów we właściwej kolejności. assertEquals(Expected<T> expected, Actual<T> actual)Podpis wykorzystuje kompilator do egzekwowania prawidłowego użytkowania, co jest zupełnie inne podejście. Możesz zoptymalizować to podejście pod kątem zwięzłości, np. expect(10).equalsActual(x)Ale to nie było pytanie…
Holger

6
Ponadto w tym konkretnym przypadku (==) kolejność argumentów nie ma znaczenia dla wartości końcowej. Kolejność ma znaczenie tylko dla efektu ubocznego (zgłoszenie awarii). Przy zamawianiu sprawy może to mieć (marginalnie) większy sens. Na przykład strcpy (dest, src).
Kristian H

1
Nie mogę się bardziej zgodzić, zwłaszcza w części dotyczącej powielania i łączenia ... Jeśli za każdym razem, gdy parametr funkcji zmienia swoją nazwę, nazwa funkcji również musiałaby się zmienić, musiałbyś śledzić wszystkie zastosowania tej funkcji i zmień je również ... To by było mnóstwo przełomowych zmian dla mnie, mojego zespołu i wszystkich innych, którzy używają naszego kodu jako zależności ...
mrsmn

20

Pytasz o długotrwałą debatę w programowaniu. Ile gadatliwości jest dobre? Ogólnie rzecz biorąc, programiści stwierdzili, że dodatkowa gadatliwość nazywania argumentów nie jest tego warta.

Gadatliwość nie zawsze oznacza większą przejrzystość. Rozważać

copyFromSourceStreamToDestinationStreamWithoutBlocking(fileStreamFromChoosePreferredOutputDialog, heuristicallyDecidedSourceFileHandle)

przeciw

copy(output, source)

Oba zawierają ten sam błąd, ale czy rzeczywiście ułatwiliśmy jego znalezienie? Zasadniczo najłatwiej jest debugować, gdy wszystko jest maksymalnie zwięzłe, z wyjątkiem kilku rzeczy, które zawierają błąd, a te są wystarczająco szczegółowe, aby powiedzieć ci, co poszło nie tak.

Istnieje długa historia dodawania gadatliwości. Na przykład istnieje ogólnie niepopularna „ notacja węgierska ”, która dała nam wspaniałe nazwy, takie jak lpszName. To na ogół poszło na marne w ogólnej populacji programistów. Jednak dodawanie znaków do nazw zmiennych członków (takich jak mNamelub m_Namelub name_) nadal cieszy się popularnością w niektórych kręgach. Inni całkowicie to porzucili. Zdarza mi się pracować na bazie kodu symulacji fizyki, której dokumenty w stylu kodowania wymagają, aby każda funkcja zwracająca wektor musiała określać ramkę wektora w wywołaniu funkcji ( getPositionECEF).

Być może zainteresują Cię niektóre języki popularne w Apple. Cel-C obejmuje nazwy argumentów jako część podpisu funkcji (funkcja [atm withdrawFundsFrom: account usingPin: userProvidedPin]jest zapisana w dokumentacji jako withdrawFundsFrom:usingPin:. To jest nazwa funkcji). Swift podjął podobny zestaw decyzji, wymagając umieszczenia nazw argumentów w wywołaniach funkcji ( greet(person: "Bob", day: "Tuesday")).


13
Pomijając wszystkie inne kwestie, byłoby o wiele łatwiej je odczytać, gdyby copyFromSourceStreamToDestinationStreamWithoutBlocking(fileStreamFromChoosePreferredOutputDialog, heuristicallyDecidedSourceFileHandle)zostały napisane copy_from_source_stream_to_destination_stream_without_blocking(file_stream_from_choose_preferred_output_dialog, heuristically_decided_source_file_handle). Widzisz, o ile było to łatwiejsze ! Jest tak, ponieważ zbyt łatwo jest przeoczyć małe zmiany w połowie tej humungousunbrokenwordsalad i dłużej zajmuje ustalenie, gdzie są granice słów. Smashing dezorientuje.
tchrist

1
Składnia obj-C withdrawFundsFrom: account usingPin: userProvidedPinjest faktycznie zapożyczona z SmallTalk.
joH1

14
@ tchrist, bądź ostrożny, upewniając się, że masz rację na tematy związane z świętymi wojnami. Druga strona nie zawsze jest w błędzie.
Cort Ammon

3
@ tchrist Addingunderscoresnakesthingseasiertoreadnotharderasyouseemanipuluje argumentem. W odpowiedzi użyto wielkich liter, które pomijasz. AddingCapitalizationMakesThingsEasyEnoughToReadAsYouCanSeeHere. Po drugie, 9 razy na 10, nazwa nigdy nie powinna rosnąć poza [verb][adjective][noun](gdzie każdy blok jest opcjonalny), format, który jest dobrze czytelny przy użyciu wielkich liter:ReadSimpleName
Flater

5
@tchrist - nauka twoich badań ( bezpłatny link tekstowy ) po prostu pokazuje, że programiści przeszkoleni w używaniu stylu podkreślenia szybciej czytają styl podkreślenia niż wielbłąd. Dane pokazują również, że różnica jest mniejsza w przypadku bardziej doświadczonych przedmiotów (a większość przedmiotów będących studentami sugeruje, że nawet ci nie byli szczególnie doświadczeni). Nie oznacza to, że programiści, którzy spędzili więcej czasu na korzystaniu ze skrzyni wielbłądów, również dadzą ten sam wynik.
Jules

8

Autor „Czystego kodu” wskazuje na uzasadniony problem, ale jego sugerowane rozwiązanie jest raczej nieeleganckie. Zwykle istnieją lepsze sposoby poprawy niejasnych nazw metod.

Ma rację, że assertEquals(z bibliotek testowych jednostek stylu xUnit) nie wyjaśnia, który argument jest oczekiwany, a który rzeczywisty. To też mnie ugryzło! Wiele bibliotek testów jednostkowych zauważyło ten problem i wprowadziło alternatywne składnie, takie jak:

actual.Should().Be(expected);

Lub podobne. Co z pewnością jest o wiele wyraźniejsze niż, assertEqualsale także o wiele lepsze niż assertExpectedEqualsActual. I jest również o wiele bardziej składalny.


1
Jestem analem i postępuję zgodnie z zalecaną kolejnością, ale wydaje mi się, że jeśli spodziewam się wyniku fun(x)5, to co może pójść nie tak, jeśli odwrócisz kolejność - assert(fun(x), 5)? Jak cię ugryzło?
emory

3
@emory Wiem, że jUnit (przynajmniej) buduje dokładny komunikat o błędzie na podstawie wartości expectedi actual, więc ich odwrócenie może spowodować, że komunikat nie będzie dokładny. Ale zgadzam się, że brzmi to bardziej naturalnie :)
joH1

@ joH1 wydaje mi się słaby. Kod braku zawiedzie i przekazywanie kodu przejdzie czy ty assert(expected, observed)lub assert(observed, expected). Lepszym przykładem byłoby coś takiego locateLatitudeLongitude- jeśli odwrócisz współrzędne, poważnie się zepsuje.
emory

1
@emory Ludzie, którzy nie dbają o sensowne komunikaty o błędach w testach jednostkowych, właśnie dlatego mam do czynienia z „Assert.IsTrue failed” w niektórych starych bazach kodu. Debugowanie to świetna zabawa. Ale tak, w tym przypadku problem może nie być tak istotny (z wyjątkiem sytuacji, gdy wykonujemy rozmyte porównania, w których kolejność argumentów na ogół ma znaczenie). Płynne asercje są rzeczywiście świetnym sposobem na uniknięcie tego problemu, a także sprawiają, że kod jest bardziej wyrazisty (i zapewnia znacznie lepszy komunikat o błędzie podczas uruchamiania).
Voo,

@emory: Odwrócenie argumentu spowoduje, że komunikaty o błędach wprowadzą w błąd i wyślą złą ścieżkę podczas debugowania.
JacquesB

5

Próbujesz poprowadzić swoją drogę między Scyllą a Charybdą do jasności, starając się unikać bezużytecznej gadatliwości (znanej również jako bezcelowe wędrowanie), a także nadmiernej zwięzłości (znanej również jako tajemnicza zwięzłość).

Musimy więc przyjrzeć się interfejsowi, który chcesz ocenić, sposobowi na potwierdzenie-debugowanie, że dwa obiekty są równe.

  1. Czy jest jakaś inna funkcja, którą może brać pod uwagę arianę i nazwę?
    Nie, więc sama nazwa jest wystarczająco jasna.
  2. Czy typy mają jakieś znaczenie?
    Nie, więc zignorujmy ich. Już to zrobiłeś? Dobry.
  3. Czy jest symetryczny w swoich argumentach?
    Niemal w przypadku błędu komunikat umieszcza reprezentację każdego argumentu we własnym miejscu.

Zobaczmy więc, czy ta niewielka różnica ma jakiekolwiek znaczenie i nie jest objęta istniejącymi silnymi konwencjami.

Czy zamierzeni odbiorcy są niewygodni, jeśli argumenty zostaną przypadkowo zamienione?
Nie, programiści dostają również śledzenie stosu i muszą sprawdzić kod źródłowy, aby naprawić błąd.
Nawet bez pełnego śledzenia stosu pozycja asercji rozwiązuje to pytanie. A jeśli nawet tego brakuje i nie jest to oczywiste z przesłania, które jest, co najwyżej podwaja możliwości.

Czy kolejność argumentów jest zgodna z konwencją?
Wydaje się, że tak jest. Choć w najlepszym razie wydaje się to słabą konwencją.

Różnica wygląda więc dość nieznacznie, a porządek argumentów objęty jest wystarczająco silną konwencją, aby każda próba umieszczenia go w nazwie funkcji miała negatywną użyteczność.


cóż, kolejność może mieć znaczenie w przypadku jUnit, który buduje konkretny komunikat o błędzie z wartości expectedi actual(przynajmniej z ciągów)
joH1

Myślę, że omówiłem tę część ...
Deduplicator

pan wspomniał jednak rozważyć: assertEquals("foo", "doo")daje komunikat o błędzie jest ComparisonFailure: expected:<[f]oo> but was:<[d]oo>... Zamiana wartości byłoby odwrócić znaczenie wiadomości, że brzmi bardziej anty symetryczny do mnie. W każdym razie, jak powiedziałeś, deweloper ma inne wskaźniki, aby rozwiązać błąd, ale może wprowadzać w błąd IMHO i zajmować trochę więcej czasu na debugowanie.
joH1

Pomysł, że istnieje „konwencja” dla rozkazów argumentacyjnych, jest zabawny, biorąc pod uwagę, że oba obozy (dest, src vs. src, dest) kłóciły się o to przynajmniej tak długo, jak długo istniała składnia AT&T vs. Intel. Niepomocne komunikaty o błędach w testach jednostkowych są zarazą, którą należy wyeliminować, a nie egzekwować. To prawie tak źle, jak „Assert.IsTrue nie powiodło się” („hej, musisz przeprowadzić test jednostkowy, aby go debugować, więc po prostu uruchom go ponownie i umieść tam punkt przerwania”, „hej, i tak musisz spojrzeć na kod, więc po prostu sprawdź, czy zamówienie jest prawidłowe ”).
Voo,

@Voo: Chodzi o to, że „uszkodzenie” popełnienia błędu jest maleńkie (logika nie zależy od tego, a narzędzie wiadomości nie jest w znacznym stopniu naruszone), a podczas pisania IDE pokaże nazwę parametrów i wpisz mimo to.
Deduplicator,

3

Często nie dodaje żadnej logicznej przejrzystości.

Porównaj „Dodaj” do „AddFirstArgumentToSecondArgument”.

Jeśli potrzebujesz przeciążenia, które, powiedzmy, dodaje trzy wartości. Co miałoby więcej sensu?

Kolejne „Dodaj” z trzema argumentami?

lub

„AddFirstAndSecondAndThirdArgument”?

Nazwa metody powinna przekazywać jej logiczne znaczenie. Powinien powiedzieć, co robi. Mówienie na poziomie mikro, jakie kroki należy podjąć, nie ułatwia czytelnikowi. W razie potrzeby nazwy argumentów dostarczą dodatkowych szczegółów. Jeśli nadal potrzebujesz więcej szczegółów, kod będzie dla Ciebie odpowiedni.


4
Addsugeruje operację przemienną. OP dotyczy sytuacji, w których zamówienie ma znaczenie.
Rosie F

W Swift możesz na przykład wywołać add (5, to: x) lub add (5, plus: 7, to: x) lub add (5, plus: 7, dając: x), jeśli zdefiniujesz funkcję add () odpowiednio.
gnasher729

Trzecie przeciążenie powinno nosić nazwę „Sum”
StingyJack

@StringyJack Hmm .. Suma nie jest instrukcją, jest rzeczownikiem, co czyni ją mniej odpowiednią dla nazwy metody. Ale jeśli tak się czujesz i jeśli chcesz być purystą, wersja z dwoma argumentami również powinna mieć nazwę Sum. Jeśli miałbyś mieć metodę Add, powinna ona mieć jeden argument dodany do samej instancji obiektu (który musiałby być typem liczbowym lub wektorowym). Dwie lub więcej odmian argumentów (jakkolwiek byś je nazwał) byłyby statyczne. Wtedy 3 lub więcej wersji argumentów byłoby zbędnych i zaimplementowalibyśmy operator plus: - |
Martin Maat

1
@Martin Poczekaj co? sumjest czasownikiem doskonale buntowniczym . Jest to szczególnie powszechne w zdaniu „podsumować”.
Voo,

2

Chciałbym dodać coś, na co wskazują inne odpowiedzi, ale nie sądzę, by zostało to wyraźnie wymienione:

@puck mówi: „Nadal nie ma gwarancji, że pierwszy wymieniony argument w nazwie funkcji jest naprawdę pierwszym parametrem”.

@cbojar mówi „Używaj typów zamiast niejednoznacznych argumentów”

Problem polega na tym, że języki programowania nie rozumieją nazw: są one po prostu traktowane jako nieprzezroczyste, atomowe symbole. Dlatego, podobnie jak w przypadku komentarzy do kodu, niekoniecznie istnieje korelacja między nazwą funkcji a jej faktycznym działaniem.

Porównaj assertExpectedEqualsActual(foo, bar)z niektórymi alternatywami (z tej strony i gdzie indziej), takimi jak:

# Putting the arguments in a labelled structure
assertEquals({expected: foo, actual: bar})

# Using a keyword arguments language feature
assertEquals(expected=foo, actual=bar)

# Giving the arguments different types, forcing us to wrap them
assertEquals(Expected(foo), Actual(bar))

# Breaking the symmetry and attaching the code to one of the arguments
bar.Should().Be(foo)

Wszystkie mają większą strukturę niż pełna nazwa, co nadaje temu językowi coś nieprzejrzystego. Definicja i użycie funkcji zależy również od tej struktury, więc nie może ona zsynchronizować się z tym, co robi implementacja (jak nazwa lub komentarz może).

Kiedy napotykam lub widzę taki problem, zanim sfrustruję swój komputer, najpierw zastanawiam się, czy to „uczciwe” obwinianie maszyny. Innymi słowy, czy maszyna otrzymała wystarczającą ilość informacji, aby odróżnić to, czego chciałam od tego, o co prosiłam?

Takie wezwanie assertEqual(expected, actual)ma tak samo sens, jak assertEqual(actual, expected), więc łatwo jest je pomieszać, a maszyna pługa i zrobić coś złego. Jeśli użyliśmy assertExpectedEqualsActualzamiast, może to uczynić nas mniej prawdopodobne, aby popełnić błąd, ale to nie daje więcej informacji do urządzenia (nie można zrozumieć po angielsku, a wybór nazwy nie powinna mieć wpływu na semantykę).

To, co sprawia, że ​​podejście „ustrukturyzowane” jest bardziej preferowane, takie jak argumenty słów kluczowych, pola oznaczone etykietami, różne typy itp., Polega na tym, że dodatkowe informacje są również do odczytu maszynowego , dzięki czemu możemy wykryć nieprawidłowe użycie maszyny i pomóc nam zrobić wszystko dobrze. assertEqualSprawa nie jest tak źle, skoro jedynym problemem byłoby niedokładne wiadomości. Bardziej złowrogi może być przykład String replace(String old, String new, String content), który łatwo pomylić z String replace(String content, String old, String new)którym ma zupełnie inne znaczenie. Prostym rozwiązaniem byłoby zabranie pary [old, new], która sprawiłaby, że błędy natychmiast spowodowałyby błąd (nawet bez typów).

Zauważ, że nawet w przypadku typów możemy nie powiedzieć „maszynie, co chcemy”. Na przykład anty-wzorzec zwany „programowaniem ciągłym” traktuje wszystkie dane jako ciągi znaków, co ułatwia pomieszanie argumentów (jak w tym przypadku), zapomnienie wykonania jakiegoś kroku (np. Ucieczkę), przypadkowe złamanie niezmienników (np. co nie do rozdzielenia JSON) itp.

Jest to również związane z „ślepotą logiczną”, w której obliczamy kilka wartości logicznych (lub liczb itp.) W jednej części kodu, ale przy próbie użycia ich w innej nie jest jasne, co tak naprawdę reprezentują, czy mamy pomieszane itp. Porównaj to np. z różnymi wyliczeniami, które mają opisowe nazwy (np. LOGGING_DISABLEDzamiast false) i które powodują komunikat o błędzie, jeśli się pomieszamy.


1

ponieważ eliminuje to konieczność pamiętania, gdzie idą argumenty

Czy to naprawdę Nadal nie ma gwarancji, że pierwszy wymieniony argument w nazwie funkcji jest naprawdę pierwszym parametrem. Lepiej to poszukaj (lub pozwól, aby IDE to zrobiło) i pozostań przy rozsądnych nazwach, niż ślepo polegaj na dość niemądrych nazwach.

Jeśli czytasz kod, powinieneś łatwo zobaczyć, co się stanie, gdy parametry zostaną nazwane tak, jak powinny. copy(source, destination)jest o wiele łatwiejszy do zrozumienia niż coś takiego copyFromTheFirstLocationToTheSecondLocation(placeA, placeB).

Dlaczego koderzy nie przyjmują tego pierwszego, jeśli jest, jak twierdzi autor, jaśniejszy od drugiego?

Ponieważ istnieją różne punkty widzenia na różne style i można znaleźć x autorów innych artykułów, które twierdzą inaczej. Zwariowałbyś, próbując śledzić wszystko, co ktoś gdzieś pisze ;-)


0

Zgadzam się, że kodowanie nazw parametrów w nazwach funkcji sprawia, że ​​pisanie i używanie funkcji jest bardziej intuicyjne.

copyFromSourceToDestination( // "...ahh yes, the source directory goes first"

Łatwo zapomnieć o uporządkowaniu argumentów w funkcjach i poleceniach powłoki, a wielu programistów polega na funkcjach IDE lub odwołaniach do funkcji z tego powodu. Posiadanie argumentów opisanych w nazwie byłoby wymownym rozwiązaniem tej zależności.

Jednak po napisaniu opis argumentów staje się zbędny dla następnego programisty, który musi przeczytać instrukcję, ponieważ w większości przypadków zostaną użyte zmienne nazwane.

copy(sourceDir, destinationDir); // "...makes sense"

Zwięzłość tego zwycięży większość programistów, a ja osobiście łatwiej mi to czytać.

EDYCJA: Jak wskazał @Blrfl, kodowanie parametrów wcale nie jest tak „intuicyjne”, ponieważ trzeba przede wszystkim zapamiętać nazwę funkcji. Wymaga to wyszukania odniesień do funkcji lub uzyskania pomocy z IDE, które prawdopodobnie dostarczy informacji o porządkowaniu parametrów.


9
Więc jeśli mogę grać adwokata diabła przez minutę: jest to intuicyjne tylko wtedy, gdy znasz pełną nazwę funkcji. Jeśli wiesz, że istnieje funkcja kopiowania i nie pamiętasz, czy to jest, copyFromSourceToDestinationczy copyToDestinationFromSourcetwoje wybory znajdują ją metodą prób i błędów lub czytasz materiał referencyjny. IDE, które mogą uzupełniać częściowe nazwy, to tylko automatyczna wersja tych ostatnich.
Blrfl

@Blrfl Chodzi o to, copyFromSourceToDestinationże jeśli uważasz, że tak copyToDestinationFromSource, kompilator znajdzie twój błąd, ale jeśli zostanie wywołany copy, nie będzie. Odczytywanie parametrów procedury kopiowania w niewłaściwy sposób jest łatwe, ponieważ strcpy, strcat itp. Stanowią precedens. Czy ten zwięzły jest łatwiejszy do odczytania? Czy mergeLists (lista A, lista B, lista C) tworzy listę A z listy B i listy C, czy czyta listę A i listę B i zapisuje listę C?
Rosie F

4
@RosieF Gdybym nie był pewien, co oznaczają argumenty, przeczytałbym dokumentację przed napisaniem kodu. Poza tym, nawet w przypadku bardziej szczegółowych nazw funkcji, wciąż jest miejsce na interpretację tego, co właściwie jest kolejność. Ktoś, kto rzuci okiem na kod, nie będzie w stanie wyczuć, że ustaliłeś konwencję, że to, co jest w nazwie funkcji, odzwierciedla kolejność argumentów. Nadal będą musieli to wiedzieć wcześniej lub przeczytać dokumenty.
Blrfl,

OTOH, destinationDir.copy (sourceDir); // „... ma większy sens”
Kristian H

1
@KristianH W jakim kierunku dir1.copy(dir2)działa? Brak pomysłu. Co dir1.copyTo(dir2)?
maaartinus
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.