Obecnie sprawdzam kod i jedną z rzeczy, które zauważam, jest liczba wyjątków, w których komunikat o wyjątku wydaje się powtarzać, gdzie wystąpił wyjątek. na przykład
throw new Exception("BulletListControl: CreateChildControls failed.");
Wszystkie trzy elementy w tej wiadomości mogę opracować na podstawie reszty wyjątku. Znam klasę i metodę ze śledzenia stosu i wiem, że zawiodła (ponieważ mam wyjątek).
Sprawiło, że pomyślałem o tym, jaką wiadomość umieszczam w wiadomościach wyjątkowych. Najpierw tworzę klasę wyjątków, jeśli jeszcze nie istnieje, z ogólnego powodu (np PropertyNotFoundException
. Dlaczego ), a następnie, gdy ją wyrzucam, komunikat wskazuje, co poszło źle (np. „Nie można znaleźć właściwości„ IDontExist ”w węźle 1234 „- co ). Gdzie jest w StackTrace
. Kiedy może zakończyć się w dzienniku (jeśli dotyczy). Jak jest deweloper wypracować (i naprawić)
Czy masz jeszcze jakieś wskazówki dotyczące zgłaszania wyjątków? W szczególności w odniesieniu do tworzenia nowych typów i komunikatu wyjątku.
źródło
Odpowiedzi:
Swoją odpowiedź skieruję bardziej na to, co nastąpi po wyjątku: po co to jest dobre i jak powinno się zachowywać oprogramowanie, co użytkownicy powinni zrobić z wyjątkiem? Świetną techniką, na którą natknąłem się na początku mojej kariery, było zawsze zgłaszanie problemów i błędów w 3 częściach: kontekst, problem i rozwiązanie. Korzystanie z tej przewagi ogromnie zmienia obsługę błędów i sprawia, że oprogramowanie jest znacznie lepsze dla operatorów.
Oto kilka przykładów.
W takim przypadku operator dokładnie wie, co zrobić i na jaki plik należy to zmienić. Wiedzą również, że zmiany w puli połączeń nie zostały przyjęte i powinny zostać powtórzone.
Piszę systemy po stronie serwera, a moi operatorzy są zorientowani na technologię pierwszej linii. Napisałbym inaczej w przypadku programów komputerowych, które mają różnych odbiorców, ale zawierają te same informacje.
Gdy używa się tej techniki, dzieje się kilka cudownych rzeczy. Deweloper oprogramowania jest często najlepiej przygotowany do rozwiązywania problemów we własnym kodzie, więc kodowanie rozwiązań w ten sposób podczas pisania kodu jest ogromną korzyścią dla użytkowników końcowych, którzy mają trudności ze znalezieniem rozwiązań, ponieważ często brakuje im informacji o co dokładnie robiło oprogramowanie. Każdy, kto kiedykolwiek przeczytał komunikat o błędzie Oracle, będzie wiedział, co mam na myśli.
Drugą cudowną rzeczą, która przychodzi na myśl, jest próba opisania rozwiązania w twoim wyjątku i piszesz „Sprawdź X, a jeśli A to B jeszcze C”. Jest to bardzo wyraźny i oczywisty znak, że Twój wyjątek jest sprawdzany w niewłaściwym miejscu. Wy, programiści, macie możliwość porównywania rzeczy w kodzie, więc „jeśli” instrukcje powinny być uruchamiane w kodzie, po co angażować użytkownika w coś, co można zautomatyzować? Możliwe, że jest to z głębszego kodu, a ktoś zrobił leniwą rzecz i wyrzucił wyjątek IOException z dowolnej liczby metod i wyłapał potencjalne błędy z każdego z nich w bloku wywołującego kodu, który nie może odpowiednio opisać, co poszło źle, co konkretniekontekst jest i jak to naprawić. To zachęca Cię do pisania drobniejszych błędów ziarna, wychwytywania i obsługiwania ich we właściwym miejscu w kodzie, abyś mógł poprawnie wyartykułować kroki, które powinien podjąć operator.
W jednej firmie mieliśmy najlepszych operatorów, którzy naprawdę dobrze poznali oprogramowanie i prowadzili własną „księgę”, która poprawiła nasze zgłaszanie błędów i sugerowało rozwiązania. Aby to rozpoznać, oprogramowanie zaczęło w wyjątkowych przypadkach włączać linki wiki do księgi głównej, tak aby dostępne było podstawowe wyjaśnienie, a także łącza do bardziej zaawansowanych dyskusji i spostrzeżeń operatorów.
Jeśli masz doświadczenie w wypróbowaniu tej techniki, staje się o wiele bardziej oczywiste, jak powinieneś nazwać swoje wyjątki w kodzie podczas tworzenia własnego. NonRecoverableConfigurationReadFailedException staje się trochę skrótem tego, co zamierzasz pełniej opisać operatorowi. Lubię być gadatliwy i myślę, że będzie to łatwiejsze dla następnego programisty, który dotknie mojego kodu do interpretacji.
źródło
FileNotFound
lubConnectException
wiesz, co robić))W tym najnowszym pytaniu zwróciłem uwagę, że wyjątki w ogóle nie powinny zawierać wiadomości. Moim zdaniem fakt, że tak robią, jest ogromnym nieporozumieniem. Proponuję to
Wyjątek powinien zawierać w obrębie własnych zmiennych składowych jak najwięcej szczegółów na temat dokładnie tego, co się stało; na przykład a
IndexOutOfRangeException
powinien zawierać wartość indeksu, która została uznana za niepoprawną, a także górne i dolne wartości, które były ważne w momencie zgłoszenia wyjątku. W ten sposób, korzystając z odbicia, możesz mieć automatycznie skonstruowany komunikat, który brzmi następująco:IndexOutOfRangeException: index = -1; min=0; max=5
i to, wraz ze śledzeniem stosu, powinny stanowić wszystkie obiektywne informacje, których potrzebujesz, aby rozwiązać problem. Sformatowanie go w ładną wiadomość, np. „Indeks -1 nie był między 0 a 5”, nie dodaje żadnej wartości.W twoim konkretnym przykładzie
NodePropertyNotFoundException
klasa zawierałaby nazwę właściwości, która nie została znaleziona, oraz odwołanie do węzła, który nie zawierał właściwości. Jest to ważne: należy nie zawierają nazwę węzła; powinien zawierać odniesienie do faktycznego węzła. W twoim konkretnym przypadku może to nie być konieczne, ale jest to kwestia zasady i preferowanego sposobu myślenia: podstawową troską przy konstruowaniu wyjątku jest to, że musi być użyteczny przez kod, który może go złapać. Użycie przez ludzi jest ważnym, ale jedynie drugorzędnym problemem.Zapobiega to bardzo frustrującej sytuacji, której być może doświadczyłeś w pewnym momencie swojej kariery zawodowej, w której możesz zauważyć wyjątek zawierający istotne informacje o tym, co wydarzyło się w tekście wiadomości, ale nie w jej zmiennych członkowskich, więc musiałem parsować ciąg tekstowy, aby dowiedzieć się, co się stało, mając nadzieję, że tekst wiadomości pozostanie taki sam w przyszłych wersjach warstwy podstawowej, i modląc się, aby tekst wiadomości nie był w jakimś obcym języku, gdy twój program jest uruchomić w innych krajach.
Oczywiście, ponieważ nazwa klasy wyjątku jest komunikatem wyjątku (a zmienne składowe wyjątku są szczegółowymi szczegółami), oznacza to, że potrzebujesz wielu różnych wyjątków, aby przekazać wszystkie różne komunikaty, oraz w porządku.
Czasami, kiedy piszemy kod, spotykamy się z błędną sytuacją, w której chcemy po prostu szybko zakodować
throw
instrukcję i kontynuować pisanie kodu zamiast przerywać to, co robimy, aby stworzyć nową klasę wyjątków, abyśmy mogli rzuć to tam. W tych przypadkach mamGenericException
klasę, która faktycznie akceptuje komunikat łańcuchowy jako parametr czasu budowy, ale konstruktor tej wyjątkowej klasy jest ozdobiony wielkim, wielkim, jasnym fioletowymFIXME XXX TODO
komentarzem stwierdzającym, że każda instancja tej klasy musi być zastąpione wystąpieniem jakiejś bardziej wyspecjalizowanej klasy wyjątków przed wydaniem systemu, najlepiej przed zatwierdzeniem kodu.źródło
node
obiekt jest chroniony przez klauzulę use-disposable (w C #) lub try-with-resources (w Javie): obiekt przechowywany z wyjątkiem zostałby unieszkodliwiony / zamknięty, co czyni go nielegalnym aby uzyskać do niego dostęp, aby uzyskać z niego użyteczne informacje w miejscu, w którym obsługiwany jest wyjątek. Przypuszczam, że w tych przypadkach jakieś streszczenie podsumowania obiektu powinno być przechowywane w ramach wyjątku, zamiast samego obiektu. Nie mogę wymyślić głupiego sposobu, aby ogólnie poradzić sobie z tym we wszystkich przypadkach.Zasadą ogólną jest, że wyjątek powinien pomóc programistom w określeniu przyczyny poprzez podanie użytecznych informacji (oczekiwane wartości, rzeczywista wartość, możliwe przyczyny / rozwiązanie itp.).
Nowe typy wyjątków powinny być tworzone, gdy żaden z wbudowanych typów nie ma sensu . Określony typ umożliwia innym programistom wyłapanie określonego wyjątku i obsłużenie go. Jeśli programista będzie wiedział, jak obsłużyć wyjątek, ale taki jest typ
Exception
, nie będzie w stanie odpowiednio go obsłużyć.źródło
W .NET nigdy
throw new Exception("...")
(jak pokazał autor pytania). Wyjątek jest głównym typem wyjątku i nie powinien być nigdy zgłaszany bezpośrednio. Zamiast tego wyrzuć jeden z pochodnych typów wyjątków .NET lub utwórz własny niestandardowy wyjątek, który wywodzi się z wyjątku (lub innego typu wyjątku).Dlaczego nie rzucić wyjątku? Ponieważ zgłoszenie wyjątku
catch(Exception ex) { ... }
nie ma wpływu na opis Twojego wyjątku i zmusza Twój kod wywołujący do napisania kodu, co na ogół nie jest dobrą rzeczą! :-).źródło
Rzeczy, których chcesz „dodać” do wyjątku, to te elementy danych, które nie są nieodłączne od wyjątku lub śledzenia stosu. To, czy stanowią one część „wiadomości”, czy muszą zostać dołączone po zalogowaniu, jest interesującym pytaniem.
Jak już zauważyłeś, wyjątek mówi ci co, stacktrace prawdopodobnie mówi ci gdzie, ale „dlaczego” może być bardziej zaangażowane (powinno być, można mieć nadzieję), niż po prostu zajrzeć do linii lub dwóch i powiedzieć „ doh! Oczywiście ". Jest to tym bardziej prawdziwe przy logowaniu błędów w kodzie produkcyjnym - zbyt często gryzły mnie złe dane, które trafiły do działającego systemu, który nie istnieje w naszych systemach testowych. Coś tak prostego, jak znajomość identyfikatora rekordu w bazie danych, który powoduje (lub przyczynia się) do błędu, może zaoszczędzić znaczną ilość czasu.
Więc ... Albo na liście, albo w .NET, dodany do zbieranych danych wyjątków (por. @Plip!):
Niektóre rzeczy, oczywiście, nie będziesz wiedział, że potrzebujesz, dopóki nie będziesz ich mieć w swoim początkowym raporcie / dzienniku błędów. Niektóre rzeczy, o których nie zdajesz sobie sprawy, że możesz je zdobyć, dopóki ich nie potrzebujesz.
źródło
Jakie są wyjątki dla ?
(1) Mówienie użytkownikowi, że coś poszło nie tak?
To powinno być ostatecznością, ponieważ Twój kod powinien interweniować i pokazywać im coś „ładniejszego” niż wyjątek.
Komunikat „błąd” powinien jasno i zwięźle wskazywać, co poszło nie tak i co użytkownik może zrobić, aby wyjść z błędu.
np. „Proszę nie naciskać tego przycisku ponownie”
(2) Mówienie deweloperowi, gdy popełnił błąd?
Jest to rodzaj rzeczy, którą logujesz do pliku w celu późniejszej analizy. Śledzenie stosu powie Developer gdzie kod złamał; komunikat powinien ponownie wskazywać, co poszło nie tak.
(3) Mówienie programowi obsługi wyjątków (tj. Kodu), że coś poszło nie tak?
Typ wyjątku, który zadecyduje wyjątek obsługi dostanie na to patrzeć i właściwości zdefiniowane na obiekt wyjątku pozwolą Wózek do czynienia z nim.
Przesłanie wyjątku jest całkowicie nieistotne .
źródło
Nie twórz nowych typów, jeśli możesz pomóc. Mogą powodować dodatkowe zamieszanie, złożoność i prowadzić do utrzymania większej liczby kodów. Mogą sprawić, że Twój kod będzie musiał zostać rozszerzony. Projektowanie hierarchii wyjątków wymaga dużo pracy i testowania. To nie jest myśl następcza. Często najlepiej jest korzystać z wbudowanej hierarchii wyjątków językowych.
Treść wiadomości wyjątku zależy od odbiorcy wiadomości - więc musisz postawić się w sytuacji tej osoby.
Inżynier wsparcia musi być w stanie jak najszybciej zidentyfikować źródło błędu. Dołącz krótki opisowy ciąg oraz wszelkie dane, które mogą pomóc w rozwiązaniu problemu. Zawsze dołączaj ślad stosu - jeśli możesz - będzie to jedyne prawdziwe źródło informacji.
Prezentowanie błędów ogólnym użytkownikom systemu zależy od rodzaju błędu: jeśli użytkownik może naprawić problem, na przykład poprzez podanie różnych danych wejściowych, wymagany jest zwięzły opisowy komunikat. Jeśli użytkownik nie może rozwiązać problemu, najlepiej poinformować, że wystąpił błąd, i zaloguj się / wyślij błąd do pomocy technicznej (korzystając z powyższych wskazówek).
Ponadto - nie wyrzucaj dużego „BŁĘDU HALTU!” Ikona. To błąd - to nie koniec świata.
Podsumowując: pomyśl o aktorach i zastosuj przypadki dla swojego systemu. Postaw się w butach tego użytkownika. Być pomocnym. Bądź miły. Pomyśl o tym z góry w projekcie systemu. Z perspektywy użytkowników - te wyjątki i sposób, w jaki system je obsługuje, są tak samo ważne jak normalne przypadki w twoim systemie.
źródło