To ostatnio dużo robię.
Przykład:
setCircle(circle, i, { current }) {
if (i == current) {
circle.src = 'images/25CE.svg'
circle.alt = 'Now picking'
} else if (i < current) {
circle.src = 'images/25C9.svg'
circle.alt = 'Pick failed'
} else if (i > current) {
circle.src = 'images/25CB.svg'
circle.alt = 'Pick chance'
}
}
Często drabina if / else jest znacznie bardziej skomplikowana niż ta ...
Zobacz ostatnią klauzulę? Jest zbędny. Drabina ma ostatecznie uchwycić wszystkie możliwe warunki. W ten sposób można go przepisać w ten sposób:
setCircle(circle, i, { current }) {
if (i == current) {
circle.src = 'images/25CE.svg'
circle.alt = 'Now picking'
} else if (i < current) {
circle.src = 'images/25C9.svg'
circle.alt = 'Pick failed'
} else {
circle.src = 'images/25CB.svg'
circle.alt = 'Pick chance'
}
}
Tak pisałem kod, ale nie lubię tego stylu. Moja skarga polega na tym, że warunek, w którym zostanie wykonana ostatnia część kodu, nie jest oczywisty z kodu. W ten sposób zacząłem pisać ten warunek, aby był bardziej widoczny.
Jednak:
- Wyraźnie napisanie ostatecznego wyczerpującego warunku jest moim własnym pomysłem i mam złe doświadczenia z własnymi pomysłami - zwykle ludzie krzyczą na mnie o tym, jak okropne jest to, co robię - i (czasami dużo) później dowiaduję się, że to rzeczywiście było nieoptymalny;
- Jedna wskazówka, dlaczego może to być zły pomysł: nie dotyczy JavaScript, ale w innych językach kompilatory mają tendencję do wydawania ostrzeżeń, a nawet błędów dotyczących kontrolowania osiągnięcia funkcji. Sugerowanie zrobienia czegoś takiego może nie być zbyt popularne lub robię to źle.
- Skargi kompilatora sprawiły, że czasami napisałem końcowy warunek w komentarzu, ale myślę, że jest to okropne, ponieważ komentarze, w przeciwieństwie do kodu, nie mają wpływu na rzeczywistą semantykę programu:
} else { // i > current
circle.src = 'images/25CB.svg'
circle.alt = 'Pick chance'
}
Czy coś brakuje? A może robienie tego, co opisałem, to zły pomysł?
Odpowiedzi:
Oba podejście jest ważne. Ale przyjrzyjmy się bliżej zaletom i wadom.
Dla
if
łańcucha z tak trywialnymi warunkami, jak tutaj, tak naprawdę nie ma znaczenia:else
rozrachunku dla czytelnika oczywiste jest, w jakim stanie zostaje wyzwolona reszta;else if
, dla czytelnika jest oczywiste, że nieelse
potrzebujesz żadnych dodatkowych , ponieważ wszystko to omówiłeś.Istnieje jednak wiele
if
łańcuchów, które opierają się na bardziej złożonych warunkach, łącząc stany kilku zmiennych, być może ze złożonym wyrażeniem logicznym. W tym przypadku jest to mniej oczywiste. A tutaj konsekwencja każdego stylu:else
: masz pewność, że jeden z oddziałów jest zajęty. Jeśli zdarzy się, że zapomniałeś o jednej sprawie, przejdzie ona przez ostatnią gałąź, więc podczas debugowania, jeśli wybrano ostatnią gałąź i oczekiwałeś czegoś innego, szybko się domyślisz.else if
: musisz wyprowadzić nadmiarowy warunek do kodu, a to stwarza potencjalne źródło błędów z ryzykiem nieobjęcia wszystkich przypadków. Ponadto, jeśli przegapiłeś przypadek, nic nie zostanie wykonane i może być trudniej dowiedzieć się, że czegoś brakowało (np. Jeśli niektóre zmienne, które miały być ustawione, zachowają wartości z poprzednich iteracji).Zatem ostateczny stan nadmiarowy jest źródłem ryzyka. Właśnie dlatego wolałbym przejść do finału
else
.Edycja: kodowanie o wysokiej niezawodności
Jeśli tworzysz z myślą o wysokiej niezawodności, możesz zainteresować się innym wariantem: uzupełnieniem zbędnego jawnego finału
else if
finałemelse
w celu wychwycenia nieoczekiwanych sytuacji.To jest kodowanie obronne. Jest to zalecane przez niektóre specyfikacje bezpieczeństwa, takie jak SEI CERT lub MISRA . Niektóre narzędzia analizy statycznej implementują to jako regułę, która jest systematycznie sprawdzana (może to wyjaśniać ostrzeżenia kompilatora).
źródło
assert
finałuelse if
. Twój przewodnik po stylu może się jednak różnić w zależności od tego, czy jest to dobry pomysł. (Warunek „a”assert
nigdy nie powinien być fałszywy, chyba że programista spieprzył. Więc to przynajmniej używa tej funkcji zgodnie z jej przeznaczeniem. Ale tak wiele osób niewłaściwie z niej korzysta, że wiele sklepów zakazało jej wprost.)Coś, czego dotychczas brakuje w odpowiedziach, zależy od tego, jaki rodzaj awarii jest mniej szkodliwy.
Jeśli twoja logika jest dobra, tak naprawdę nie ma znaczenia, co robisz, ważne jest to, co się dzieje, jeśli masz błąd.
Pomijasz ostatni warunek: ostatnia opcja jest wykonywana, nawet jeśli nie jest to właściwe.
Po prostu dodajesz końcowy warunek: nie wykonuje żadnej opcji, w zależności od sytuacji może to po prostu oznaczać, że coś nie wyświetla się (niska szkoda), lub może oznaczać wyjątek zerowy odniesienia w pewnym późniejszym momencie (co może być debugowaniem ból.)
Dodajesz końcowy warunek i wyjątek: wyrzuca.
Musisz zdecydować, która z tych opcji jest najlepsza. W kodzie programistycznym uważam to za oczywiste - weźmy trzeci przypadek. Najprawdopodobniej jednak ustawiłbym koło.src na obraz błędu, a okrąg.alt na komunikat o błędzie przed wyrzuceniem - na wypadek, gdyby ktoś zdecydował się później wyłączyć twierdzenia, spowoduje to, że będzie on nieszkodliwy.
Kolejna rzecz do rozważenia - jakie są opcje odzyskiwania? Czasami nie masz ścieżki odzyskiwania. Moim zdaniem najlepszym tego przykładem jest pierwsza rakieta Ariane V. Wystąpił nieprzechwycony błąd / 0 (właściwie przepełnienie podziału), który spowodował zniszczenie wzmacniacza. W rzeczywistości kod, który się zawiesił, nie miał w tym momencie żadnego sensu, stał się dyskusyjny w chwili, gdy zapalono wzmacniacze przypinane taśmą. Gdy zaświecą się na orbitę lub boom, robisz, co możesz, nie można dopuścić do błędów. (Jeśli rakieta zbłądzi z tego powodu, zawodnik od bezpieczeństwa przekręca klucz.)
źródło
To, co zalecam, to użycie
assert
oświadczenia w końcowej wersji, w jednym z tych dwóch stylów:Lub stwierdzenie martwego kodu:
Narzędzie pokrycia kodu można często skonfigurować tak, aby ignorowało kod taki jak „aserse False” z raportu pokrycia.
Umieszczając warunek w asercji, skutecznie dokumentujesz warunek gałęzi jawnie, ale w przeciwieństwie do komentarza, warunek asercji można faktycznie sprawdzić i zakończy się niepowodzeniem, jeśli asercje będą włączone podczas programowania lub w trakcie produkcji (generalnie zalecam włączenie asercji) w produkcji, jeśli nie wpływają zbytnio na wydajność).
źródło
Zdefiniowałem makro „potwierdzone”, które ocenia warunek, aw kompilacji debugowania wpada do debugera.
Więc jeśli jestem w 100 procentach pewien, że jeden z trzech warunków musi być spełniony, piszę
Dzięki temu jest wystarczająco jasne, że jeden warunek będzie spełniony i nie jest wymagana żadna dodatkowa gałąź dla potwierdzenia.
źródło
Polecam całkowicie unikać innych . Użyj,
if
aby zadeklarować, co powinien obsługiwać blok kodu, i zakończ blok, wychodząc z funkcji.Powoduje to, że kod jest bardzo jasny:
Finał
if
jest oczywiście zbędny ... dzisiaj. Bardzo ważna może być myśl, jeśli / kiedy jakiś przyszły programista zmieni aranżację bloków. Pomocne jest więc pozostawienie go tam.źródło