Piszę prosty, mały program do przesyłania MIDI przez sieć. Wiem, że program napotka problemy z transmisją i / lub inne wyjątkowe sytuacje, których nie będę w stanie przewidzieć.
W przypadku obsługi wyjątków widzę dwa podejścia. Czy powinienem napisać program, aby:
- zawiedzie z hukiem, gdy coś pójdzie nie tak lub
- czy powinien po prostu zignorować błąd i kontynuować, kosztem integralności danych?
Którego podejścia użytkownik mógłby się spodziewać?
Czy istnieje lepszy sposób obsługi wyjątków?
Ponadto, czy na moją decyzję dotyczącą obsługi wyjątków powinien mieć wpływ to, czy mam do czynienia z połączeniem sieciowym (tj. Czymś, co do którego można zasadnie oczekiwać, że pojawią się problemy)?
exception-handling
Arlen Beiler
źródło
źródło
Odpowiedzi:
Nigdy nie należy ignorować błędu napotkanego przez program. Jako minimum powinieneś zalogować go do pliku lub innego mechanizmu w celu powiadomienia. Nie może być sporadyczne sytuacje, w których będziemy chcieli zignorować błąd ale udokumentować to! Nie pisz pustego
catch
bloku bez komentarzy wyjaśniających, dlaczego jest pusty.To, czy program powinien zawieść, czy nie, zależy w dużej mierze od kontekstu. Jeśli możesz poradzić sobie z błędem z wdziękiem, idź do niego. Jeśli jest to nieoczekiwany błąd, nastąpi awaria programu. To właściwie podstawowa obsługa wyjątków.
źródło
Nigdy nie powinieneś cicho ignorować błędów, ponieważ twój program opiera się na szeregu działań, które domyślnie zależą od wszystkiego, co minęło, zanim poszły dobrze. Jeśli coś pójdzie nie tak w kroku 3 i spróbujesz przejść do kroku 4, krok 4 rozpocznie się na podstawie nieprawidłowych założeń, co zwiększa prawdopodobieństwo, że również spowoduje błąd. (A jeśli to zignorujesz, to krok 5 generuje błąd i stamtąd zaczyna się śnieżka.)
Chodzi o to, że w miarę narastania błędów, w końcu natrafisz na błąd tak duży, że nie możesz go zignorować, ponieważ będzie on polegał na tym, że użytkownik otrzyma coś i że coś będzie całkowicie nie tak. Następnie użytkownicy narzekają na ciebie, że twój program nie działa poprawnie i musisz to naprawić. A jeśli część „daj coś użytkownikowi” znajduje się w kroku 28, a nie masz pojęcia, że pierwotny błąd powodujący cały ten bałagan był w kroku 3, ponieważ zignorowałeś błąd w kroku 3, będziesz mieć cholera, czas debugowania problemu!
Z drugiej strony, jeśli ten błąd w kroku 3 powoduje wysadzenie wszystkiego w twarz użytkownika i generuje błąd mówiący
SOMETHING WENT BADLY WRONG IN STEP 3!
(lub jego techniczny odpowiednik, ślad stosu), to wynik jest taki sam - użytkownik narzeka na ciebie program nie działa poprawnie - ale tym razem wiesz dokładnie, od czego zacząć szukać, kiedy go naprawić .EDYCJA: W odpowiedzi na komentarze, jeśli coś pójdzie nie tak, jak się spodziewałeś i wiesz, jak sobie z tym poradzić, jest inaczej. Na przykład w przypadku otrzymania źle sformułowanego komunikatu nie jest to błąd programu; to „użytkownik podał błędne dane wejściowe, których nie udało się sprawdzić”. Odpowiednią odpowiedzią jest poinformowanie użytkownika, że przekazuje ci nieprawidłowe dane wejściowe, co brzmi jak robisz. Nie ma potrzeby zawieszania się i generowania śladu stosu w takim przypadku.
źródło
Istnieją inne opcje między „wysadzeniem w powietrze” a „zignorowaniem”.
Jeśli błąd jest przewidywalny i można go uniknąć, zmień projekt lub zmodyfikuj kod, aby go uniknąć.
Jeśli błąd jest przewidywalny, ale nie da się go uniknąć, ale wiesz, co zrobić, gdy się zdarzy, złap go i poradz sobie z sytuacją. Uważaj jednak, aby nie używać wyjątków jako kontroli przepływu. W tym momencie możesz chcieć zapisać ostrzeżenie i być może powiadomić użytkownika, jeśli podejmie jakieś działania, aby uniknąć tej sytuacji w przyszłości.
Jeśli błąd jest przewidywalny, nieunikniony, a gdy się zdarzy, nic nie można zrobić, co zagwarantuje integralność danych, musisz zarejestrować błąd i wrócić do bezpiecznego stanu (który, jak powiedzieli inni, może oznaczać awarię).
Jeśli błąd nie jest czymś, czego się spodziewałeś, to naprawdę nie możesz być pewien, że możesz nawet wrócić do bezpiecznego stanu, więc najlepiej po prostu zalogować się i zawiesić.
Zasadniczo nie wychwytuj żadnych wyjątków, z którymi nie możesz nic zrobić, chyba że po prostu planujesz zalogować się i ponownie wrzucić. A w rzadkich przypadkach, gdy nie można uniknąć try-catch-ignore, dodaj przynajmniej komentarz w bloku catch, aby wyjaśnić, dlaczego.
Zobacz doskonały artykuł Erica Lipperta na temat obsługi wyjątków, aby uzyskać więcej sugestii dotyczących kategoryzacji i obsługi wyjątków.
źródło
Oto moje poglądy na pytanie:
Dobrą zasadą początkową jest szybkie zawodzenie. W szczególności nigdy nie należy pisać kodu obsługi błędów w przypadku awarii, dla których nie znasz dokładnej przyczyny.
Po zastosowaniu tej zasady możesz dodać kod odzyskiwania dla określonych napotkanych błędów. Możesz także wprowadzić kilka „bezpiecznych stanów”, do których możesz wrócić. Przerwanie programu jest w większości bezpieczne, ale czasami możesz chcieć wrócić do innego znanego dobrego stanu. Przykładem jest, w jaki sposób nowoczesny system operacyjny obsługuje szkodliwy program. Wyłącza tylko program, a nie cały system operacyjny.
Zawodząc szybko i powoli pokrywając coraz bardziej specyficzne warunki błędu, nigdy nie naruszasz integralności danych i stale przechodzisz na bardziej stabilny program.
Połknięcie błędów, tj. Próba zaplanowania błędów, dla których nie znasz dokładnej przyczyny, a zatem nie masz konkretnej strategii odzyskiwania, prowadzi tylko do coraz większej liczby pomijania błędów i obchodzenia kodu w twoim programie. Ponieważ nie można ufać, że poprzednie dane zostały poprawnie przetworzone, zaczniesz widzieć rozłożone sprawdzanie nieprawidłowych lub brakujących danych. Twoja cykliczna złożoność wymknie się spod kontroli i skończysz z wielką kulą błota.
To, czy zdajesz sobie sprawę z przypadków awarii, ma mniejsze znaczenie. Ale jeśli na przykład masz do czynienia z połączeniem sieciowym, dla którego znasz pewną liczbę stanów błędów, odłóż dodawanie obsługi błędów, aż dodasz również kod odzyskiwania. Jest to zgodne z zasadami przedstawionymi powyżej.
źródło
Nigdy nie powinieneś cicho ignorować błędów. A zwłaszcza nie kosztem integralności danych .
Program próbuje coś zrobić. Jeśli to się nie powiedzie, musisz zmierzyć się z tym faktem i coś z tym zrobić . To, co to będzie, zależy od wielu rzeczy.
W końcu użytkownik poprosił program, aby coś zrobił, a program powinien powiedzieć mu, że się nie udało. Jest wiele sposobów, jak to zrobić. Może zatrzymać się natychmiast, może nawet cofnąć już ukończone kroki lub, z drugiej strony, może kontynuować i wykonać wszystkie kroki, jakie może, a następnie poinformować użytkownika, że te kroki się powiodły, a inne nie.
Wybór sposobu zależy od tego, jak ściśle powiązane są kroki i czy prawdopodobne jest, że błąd wystąpi ponownie dla wszystkich przyszłych kroków, co z kolei może zależeć od dokładnego błędu. Jeśli wymagana jest silna integralność danych, musisz przywrócić do ostatniego spójnego stanu. Jeśli kopiujesz tylko kilka plików, możesz pominąć niektóre i po prostu powiedzieć użytkownikowi, że tych plików nie można skopiować. Nie należy po cichu pomijać plików i informować użytkownika o niczym.
Edycja reklamy, jedyną różnicą, którą się robi, jest to, że powinieneś rozważyć kilka razy, zanim zrezygnujesz i powiesz użytkownikowi, że nie działał, ponieważ w sieci prawdopodobnie wystąpią przejściowe błędy, które nie powtórzą się, jeśli spróbujesz ponownie.
źródło
Istnieje jedna klasa przypadków, w których należy ignorować błędy: gdy nic nie można zrobić w tej sytuacji, a słabe i prawdopodobnie nieprawidłowe wyniki są lepsze niż brak wyników.
Przypadek dekodowania strumienia HDMI do celów wyświetlania jest takim przypadkiem. Jeśli strumień jest zły, jest zły, krzyczenie na ten temat nie naprawi go magicznie. Robisz, co możesz, aby je wyświetlić i pozwalasz widzowi zdecydować, czy jest to dopuszczalne, czy nie.
źródło
Nie sądzę, aby program po cichu ignorował lub powodował spustoszenie, ilekroć napotkał problem.
Co robię z oprogramowaniem wewnętrznym, które piszę dla mojej firmy ...
Zależy to od błędu, powiedzmy, że jeśli jest to funkcja krytyczna, która wprowadza dane do MySQL, musi poinformować użytkownika, że się nie udało. Procedura obsługi błędów powinna próbować zebrać jak najwięcej informacji i dać użytkownikowi pomysł, jak samodzielnie poprawić błąd, aby mógł zapisać dane. Chciałbym również podać sposób, w jaki dyskretnie przesyłają nam informacje, które próbują zapisać, więc jeśli pogorszy się, możemy wprowadzić je ręcznie po usunięciu błędu.
Jeśli nie jest to funkcja krytyczna, coś, co może popełnić błąd i nie wpłynąć na ostateczny wynik tego, co próbują osiągnąć, mogę nie pokazać im komunikatu o błędzie, ale wysłać e-mail, który automatycznie wstawi go do naszego oprogramowania do śledzenia błędów lub e-mailowa grupa dystrybucyjna, która ostrzega wszystkich programistów w firmie, abyśmy byli świadomi błędu, nawet jeśli nie jest nim użytkownik. To pozwala nam naprawić zaplecze, podczas gdy w interfejsie nikt nie wie, co się dzieje.
Jedną z największych rzeczy, których staram się unikać, jest awaria programu po błędzie - niemożność odzyskania. Zawsze staram się dać użytkownikowi opcję kontynuowania bez zamykania aplikacji.
Wierzę, że jeśli nikt nie wie o błędzie - nigdy nie zostanie naprawiony. Jestem również zwolennikiem obsługi błędów, która umożliwia kontynuowanie działania aplikacji po wykryciu błędu.
Jeśli błąd jest związany z siecią - dlaczego nie wykonać funkcji prostego testu komunikacji sieciowej przed wykonaniem funkcji, aby w pierwszej kolejności uniknąć błędu? Po prostu ostrzegając użytkownika, że połączenie jest niedostępne, sprawdź swój Internet itp. Itp. I spróbuj ponownie?
źródło
Moja własna strategia polega na rozróżnianiu błędów kodowania (błędów) i błędów środowiska wykonawczego oraz, w miarę możliwości, utrudnia tworzenie błędów kodowania.
Błędy należy naprawić jak najszybciej, więc właściwe jest podejście według umowy . W C ++ lubię sprawdzać wszystkie moje warunki wstępne (dane wejściowe) za pomocą asercji u góry funkcji, aby jak najszybciej wykryć błąd i ułatwić dołączenie debuggera i naprawienie błędu. Jeśli zamiast tego programista lub tester zdecyduje się kontynuować działanie programu, utrata integralności danych stanie się ich problemem.
I przede wszystkim znajdź sposoby na uniknięcie błędu. Ścisłe przestrzeganie stałej poprawności i wybieranie typów danych odpowiednich do przechowywanych danych to dwa sposoby utrudniające tworzenie błędów. Fail-Fast jest również dobry poza kodem krytycznym dla bezpieczeństwa, który potrzebuje sposobu na odzyskanie.
W przypadku błędów środowiska wykonawczego, które mogą wystąpić w przypadku kodu wolnego od błędów, takich jak awarie komunikacji sieciowej lub szeregowej albo brakujące lub uszkodzone pliki:
źródło
Niepowodzenie jest właściwą opcją, gdy masz powody, by sądzić, że ogólny stan programu jest niestabilny i może się wydarzyć coś złego, jeśli pozwolisz mu odtąd działać. W pewnym sensie „ignorowanie” (tj., Jak zauważyli inni, rejestrowanie go gdzieś lub wyświetlanie użytkownikowi komunikatu o błędzie, a następnie kontynuowanie) jest w porządku, gdy wiadomo, że z pewnością nie można wykonać bieżącej operacji, ale program może Biegnij dalej.
źródło