Z książki Code Complete pochodzi następujący cytat:
„Postaw normalną przypadek po,
if
a nie poelse
”
Co oznacza, że należy wprowadzić wyjątki / odchylenia od standardowej ścieżki else
.
Ale Pragmatic Programmer uczy nas „wcześnie upaść” (s. 120).
Jakiej zasady powinienem przestrzegać?
if
oddziałów powróci, użyj go w pierwszej kolejności. I unikajelse
reszty kodu, już zwróciłeś, jeśli warunki wstępne zawiodły. Kod jest łatwiejszy do odczytania, mniej wcięć ...Odpowiedzi:
„Crash wcześnie” nie dotyczy tego, który wiersz kodu pojawia się wcześniej tekstowo. Informuje o wykrywaniu błędów na jak najwcześniejszym etapie przetwarzania , abyś nieumyślnie nie podejmował decyzji ani nie dokonywał obliczeń w oparciu o już uszkodzony stan.
W konstrukcie
if
/else
wykonywany jest tylko jeden blok, więc nie można powiedzieć, że żaden z nich stanowi krok „wcześniejszy” lub „późniejszy”. To, jak je zamówić, jest zatem kwestią czytelności, a „wczesne niepowodzenie” nie wchodzi w grę.źródło
if/else
konstrukcjach prawdopodobnie nie ma to znaczenia. Ale te wywoływane w pętli lub z wieloma instrukcjami w każdym bloku mogą działać szybciej z najczęściej występującym warunkiem.Jeśli twoje
else
oświadczenie zawiera tylko kod błędu, najprawdopodobniej nie powinno go tam być.Zamiast tego:
Zrób to
Nie chcesz głęboko zagnieżdżać kodu, aby po prostu włączyć sprawdzanie błędów.
I jak wszyscy inni już stwierdzili, te dwie rady nie są sprzeczne. Jeden dotyczy kolejności wykonywania , drugi dotyczy kolejności kodu .
źródło
if
i wyjątkowy przepływ w bloku po,else
nie ma zastosowania, jeśli nie maszelse
! Takie instrukcje ochronne są preferowaną formą obsługi warunków błędów w większości stylów kodowania.Powinieneś śledzić oba z nich.
Porada „Wcześniejsza awaria” / „Nieudana wczesna” oznacza, że należy jak najszybciej przetestować dane wejściowe pod kątem możliwych błędów.
Na przykład, jeśli twoja metoda przyjmuje rozmiar lub liczbę, która powinna być dodatnia (> 0), to wczesna porada „fail” oznacza, że testujesz ten warunek na początku metody, zamiast czekać na algorytm, który wygeneruje bzdury wyniki.
Porada, jak postawić normalny przypadek na pierwszym miejscu, oznacza, że jeśli testujesz na warunek, najbardziej prawdopodobna ścieżka powinna być na pierwszym miejscu. Pomaga to w wydajności (ponieważ przewidywania gałęzi procesora częściej będą poprawne) i czytelności, ponieważ nie musisz pomijać bloków kodu, gdy próbujesz dowiedzieć się, co robi funkcja w normalnym przypadku.
Ta rada tak naprawdę nie ma zastosowania podczas testowania warunku wstępnego i natychmiastowego ratowania (za pomocą twierdzeń lub
if (!precondition) throw
konstrukcji), ponieważ nie ma obsługi błędów, które można pominąć podczas czytania kodu.źródło
if(cond){/*more likely code*/}else{/*less likely code*/}
działa szybciej niż zif(!cond){/*less likely code*/}else{/*more likely code*/}
powodu przewidywania gałęzi. Sądzę, że przewidywanie gałęzi nie jest tendencyjne ani do instrukcji,if
ani doelse
oświadczenia i uwzględnia jedynie historię. Więc jeślielse
jest bardziej prawdopodobne, powinno być w stanie przewidzieć to równie dobrze. Czy to założenie jest fałszywe?Myślę, że @JackAidley powiedział już o tym , ale pozwólcie, że sformułuję to w następujący sposób:
bez wyjątków (np. C)
W zwykłym przepływie kodu masz:
W przypadku „wczesnego błędu” kod nagle wyświetla:
Jeśli zauważysz ten wzorzec -
return
w blokuelse
(a nawetif
), przerób go natychmiast, aby kod nie zawierałelse
bloku:W prawdziwym świecie…
Pozwala to uniknąć zbyt głębokiego zagnieżdżenia i spełnia warunek „wczesnego wybicia” (pomaga utrzymać umysł - i przepływ kodu - w czystości) i nie narusza „wstawienia bardziej prawdopodobnej rzeczy do
if
elementu”, ponieważ po prostu nie maelse
części .C
i porządkiZainspirowany odpowiedzią na podobne pytanie (które popełniło błąd), oto sposób czyszczenia w C. Możesz tam użyć jednego lub dwóch punktów wyjścia, tutaj jest jeden dla dwóch punktów wyjścia:
Możesz zwinąć je w jednym punkcie wyjścia, jeśli jest mniej do zrobienia:
Takie użycie
goto
jest w porządku, jeśli sobie z tym poradzisz; rada, aby nie używać,goto
jest skierowana do osób, które nie mogą jeszcze samodzielnie zdecydować, czy użycie jest dobre, dopuszczalne, złe, kod spaghetti, czy coś innego.Wyjątki
Powyższe mówi o językach bez wyjątków, które bardzo wolę siebie (mogę użyć jawnej obsługi błędów znacznie lepiej i ze znacznie mniejszym zaskoczeniem). Aby zacytować igli:
Ale oto sugestia, jak to zrobić dobrze w języku z wyjątkami i kiedy chcesz je dobrze wykorzystać:
błąd powrotu w obliczu wyjątków
Możesz zastąpić większość wczesnych
return
s rzucając wyjątek. Jednakże , twój normalny przepływ programu, czyli dowolnego strumienia kodu, w którym program nie napotka, dobrze, wyjątek ... stan błędu lub somesuch, nie powinna podnosić żadnych wyjątków.To znaczy że…
… Jest w porządku, ale…
… nie jest. Zasadniczo wyjątek nie jest elementem kontroli . To sprawia, że Operacje wyglądają na ciebie dziwnie („ci programiści Java ™ zawsze mówią nam, że te wyjątki są normalne”) i mogą utrudniać debugowanie (np. Powiedzieć IDE, aby po prostu złamało dowolny wyjątek). Wyjątki często wymagają środowiska wykonawczego, aby rozwinąć stos w celu wygenerowania śledzenia itp. Prawdopodobnie jest więcej powodów.
Sprowadza się to do: w języku wspierającym wyjątki, używaj tego, co pasuje do istniejącej logiki i stylu i wydaje się naturalne. Jeśli piszesz coś od zera, uzgodnij to wcześniej. Pisząc bibliotekę od podstaw, pomyśl o swoich konsumentach. (Nigdy nie używaj
abort()
w bibliotece…) Ale cokolwiek zrobisz, nie z reguły rzucaj wyjątek, jeśli operacja będzie kontynuowana (mniej więcej) normalnie po nim.ogólne porady wrt. Wyjątki
Postaraj się najpierw wykorzystać wszystkie wyjątki w programie uzgodnione przez cały zespół programistów. Zasadniczo je zaplanuj. Nie używaj ich w obfitości. Czasami nawet w C ++, Java ™, Python powrót błędu jest lepszy. Czasami tak nie jest; używaj ich z myślą.
źródło
goto fail;
ukrytego w tożsamości.Moim zdaniem „Warunek ochrony” jest jednym z najlepszych i najłatwiejszych sposobów na odczyt kodu. Naprawdę nienawidzę, gdy widzę
if
na początku metody i nie widzęelse
kodu, ponieważ jest on poza ekranem. Muszę przewinąć w dół, żeby zobaczyćthrow new Exception
.Umieść kontrole na początku, aby osoba czytająca kod nie musiała przeskakiwać całej metody, aby ją przeczytać, ale zawsze skanuj ją od góry do dołu.
źródło
( Odpowiedź @mirabilos jest doskonała, ale oto, jak myślę o pytaniu, aby dojść do tego samego wniosku :)
Myślę o sobie (lub kimś innym) czytającym kod mojej funkcji później. Kiedy czytam pierwszy wiersz, nie mogę poczynić żadnych założeń na temat moich danych wejściowych (poza tymi, których i tak nie sprawdzę). Więc myślę: „Ok, wiem, że będę robił różne rzeczy z moimi argumentami, ale najpierw„ wyczyśćmy je ”- tzn. Zabijaj ścieżki kontrolne, w których nie są one w moich upodobaniach.” Ale jednocześnie , Nie widzę normalnego przypadku jako czegoś, co jest uwarunkowane; chcę podkreślić, że jest normalny.
źródło
Tego rodzaju porządkowanie warunków zależy od krytyczności omawianej sekcji kodu i tego, czy można zastosować wartości domyślne.
Innymi słowy:
A. sekcja krytyczna i brak wartości domyślnych => wczesne niepowodzenie
B. sekcja niekrytyczna i wartości domyślne => Użyj wartości domyślnych w innej części
C. pomiędzy przypadkami => w razie potrzeby decyduj o każdej sprawie
źródło