Te wiadomości są dla innych programistów
Wiadomości te powinny zostać odczytane przez programistów, aby pomóc im w debugowaniu aplikacji. Może to przybierać dwie formy:
Aktywne debugowanie. W rzeczywistości uruchamiasz debuger podczas pisania kodu i próbujesz dowiedzieć się, co się stanie. W tym kontekście przydatny wyjątek poprowadzi cię, ułatwiając zrozumienie, co się dzieje źle, lub ewentualnie sugerując obejście (chociaż jest to opcjonalne).
Pasywne debugowanie. Kod działa w środowisku produkcyjnym i kończy się niepowodzeniem. Wyjątek jest rejestrowany, ale otrzymujesz tylko komunikat i ślad stosu. W tym kontekście pomocny komunikat wyjątku pomoże ci szybko zlokalizować błąd.
Ponieważ te wiadomości są często rejestrowane, oznacza to również, że nie należy w nich umieszczać poufnych informacji (takich jak klucze prywatne lub hasła, nawet jeśli użyteczne byłoby debugowanie aplikacji).
Na przykład IOSecurityException
rodzaj wyjątku zgłaszanego podczas zapisywania pliku nie jest zbyt jasny na temat problemu: czy to dlatego, że nie mamy uprawnień dostępu do pliku? A może możemy to przeczytać, ale nie napisać? A może plik nie istnieje i nie mamy uprawnień do tworzenia plików? A może jest zablokowany (mam nadzieję, że w tym przypadku wyjątek będzie inny, ale w praktyce typy mogą być czasami tajemnicze). A może Code Access Security uniemożliwia nam wykonanie jakiejkolwiek operacji we / wy?
Zamiast:
IOSecurityException: plik został znaleziony, ale odmówiono pozwolenia na odczyt jego zawartości.
jest o wiele bardziej wyraźny. W tym miejscu natychmiast wiemy, że uprawnienia do katalogu są ustawione poprawnie (w przeciwnym razie nie będziemy mogli wiedzieć, że plik istnieje), ale uprawnienia na poziomie pliku są problematyczne.
Oznacza to również, że jeśli nie możesz podać żadnych dodatkowych informacji, które nie są jeszcze w typie wyjątku, możesz pozostawić wiadomość pustą. DivisionByZeroException
jest dobrym przykładem, w którym wiadomość jest zbędna. Z drugiej strony fakt, że większość języków pozwala na zgłoszenie wyjątku bez określania jego komunikatu, dzieje się z innego powodu: albo dlatego, że domyślny komunikat jest już dostępny, albo dlatego, że zostanie wygenerowany później, jeśli zajdzie taka potrzeba (i wygenerowanie tego wiadomość jest zawarta w typie wyjątku, co ma sens, mówiąc „OOPly” ).
Pamiętaj, że ze względów technicznych (często związanych z wydajnością) niektóre wiadomości są o wiele bardziej tajemnicze niż powinny. .NET NullReferenceException
:
Odwołanie do obiektu nie jest ustawione na instancję obiektu.
jest doskonałym przykładem wiadomości, która nie jest pomocna. Pomocną wiadomością byłoby:
Odwołanie do obiektu product
nie jest ustawione na instancję obiektu po wywołaniu product.Price
.
Te wiadomości nie są dla użytkowników końcowych!
Użytkownicy końcowi nie powinni widzieć komunikatów wyjątków. Nigdy. Chociaż niektórzy programiści kończą pokazywanie tych wiadomości użytkownikom, prowadzi to do słabego doświadczenia użytkownika i frustracji. Wiadomości takie jak:
Odwołanie do obiektu nie jest ustawione na instancję obiektu.
dla użytkownika końcowego absolutnie nic i należy go za wszelką cenę unikać.
Najgorszym scenariuszem jest globalny try / catch, który zgłasza wyjątek użytkownikowi i wychodzi z aplikacji. Aplikacja, która dba o swoich użytkowników:
W pierwszej kolejności obsługuje wyjątki. Większość z nich można obsługiwać bez przeszkadzania użytkownikowi. Sieć nie działa? Dlaczego nie poczekać kilka sekund i spróbować ponownie?
Zapobiega prowadzeniu aplikacji przez użytkownika do wyjątkowego przypadku. Jeśli poprosisz użytkownika o wprowadzenie dwóch liczb i podzielenie pierwszej przez drugą, dlaczego miałbyś pozwolić użytkownikowi wprowadzić zero w drugim przypadku, aby obwinić go kilka sekund później? Co powiesz na wyróżnienie pola tekstowego na czerwono (z pomocną podpowiedzią, że liczba powinna być różna od zera) i wyłączenie przycisku sprawdzania poprawności, dopóki pole nie pozostanie czerwone?
Zaprasza użytkownika do wykonania akcji w formie, która nie jest błędem. Nie masz wystarczających uprawnień, aby uzyskać dostęp do pliku? Dlaczego nie poprosić użytkownika o przyznanie uprawnień administracyjnych lub wybrać inny plik?
Jeśli nic więcej nie działa, pokazuje pomocny, przyjazny błąd, który został napisany specjalnie w celu zmniejszenia frustracji użytkownika, pomaga użytkownikowi zrozumieć, co poszło źle i ostatecznie rozwiązuje problem, a także pomaga mu zapobiec błędowi w przyszłości (jeśli dotyczy).
W swoim pytaniu zasugerowałeś dwa wyjątki: techniczny dla programistów i jeden dla użytkowników końcowych. Chociaż jest to ważna sugestia w niektórych drobnych przypadkach, większość wyjątków powstaje na poziomie, na którym niemożliwe jest przedstawienie znaczącej wiadomości dla użytkowników. Wziąć DivisionByZeroException
i wyobrazić sobie, że nie mógł zapobiec wyjątek od tego wydarzenia i nie może poradzić sami. Kiedy podział występuje, czy środowisko (ponieważ jest to środowisko, a nie kod biznesowy, który generuje wyjątek) wie, co będzie użytecznym komunikatem dla użytkownika? Absolutnie nie:
Wystąpił podział przez zero. [DOBRZE]
Zamiast tego można pozwolić, aby wyrzucił wyjątek, a następnie złapał go na wyższym poziomie, na którym znaliśmy kontekst biznesowy i mogliśmy działać odpowiednio, aby faktycznie pomóc użytkownikowi końcowemu, pokazując w ten sposób:
Pole D13 nie może mieć wartości identycznej z wartością w polu E6, ponieważ odejmowanie tych wartości jest używane jako dzielnik. [DOBRZE]
albo może:
Wartości zgłaszane przez usługę ATP są niezgodne z lokalnymi danymi. Może to być spowodowane brakiem synchronizacji danych lokalnych. Czy chcesz zsynchronizować informacje o wysyłce i spróbować ponownie? [Tak nie]
Te wiadomości nie są przeznaczone do analizowania
Komunikaty o wyjątkach również nie powinny być analizowane ani wykorzystywane programowo. Jeśli uważasz, że dzwoniący może potrzebować dodatkowych informacji, dołącz je do wyjątku obok wiadomości. Jest to ważne, ponieważ wiadomość może ulec zmianie bez powiadomienia. Typ jest częścią interfejsu, ale komunikat nie jest: nigdy nie należy polegać na nim w przypadku obsługi wyjątków.
Wyobraź sobie komunikat wyjątku:
Upłynął limit czasu połączenia z serwerem buforowania po odczekaniu 500 ms. Zwiększ limit czasu lub sprawdź monitorowanie wydajności, aby zidentyfikować spadek wydajności serwera. Średni czas oczekiwania na buforowanie serwera wynosił 6 ms. za ostatni miesiąc, 4 ms. za ostatni tydzień i 377 ms. za ostatnią godzinę.
Chcesz wyodrębnić wartości „500”, „6”, „4” i „377”. Pomyśl trochę o podejściu, którego użyjesz do parsowania, a dopiero potem kontynuuj czytanie.
Masz pomysł Świetny.
Teraz oryginalny programista odkrył literówkę:
Connecting to the caching sever timed out after waiting [...]
powinno być:
↓
Connecting to the caching server timed out after waiting [...]
Co więcej, programista uważa, że miesiąc / tydzień / godzina nie są szczególnie istotne, więc wprowadza również dodatkową zmianę:
Średni czas oczekiwania na buforowanie serwera wynosił 6 ms. przez ostatni miesiąc, 5 ms. przez ostatnie 24 godziny i 377 ms. za ostatnią godzinę.
Co dzieje się z parsowaniem?
Zamiast analizować, możesz użyć właściwości wyjątku (które mogą zawierać wszystko, co tylko chcesz, gdy tylko dane zostaną przekształcone do postaci szeregowej):
{
message: "Connecting to the caching [...]",
properties: {
"timeout": 500,
"statistics": [
{ "timespan": 1, "unit": "month", "average-timeout": 6 },
{ "timespan": 7, "unit": "day", "average-timeout": 4 },
{ "timespan": 1, "unit": "hour", "average-timeout": 377 },
]
}
}
Jak łatwo jest teraz korzystać z tych danych?
Czasami (np. W .NET) wiadomość może być nawet przetłumaczona na język użytkownika (IMHO, tłumaczenie tych wiadomości jest absolutnie niepoprawne, ponieważ oczekuje się, że każdy programista będzie mógł czytać w języku angielskim). Analiza takich wiadomości jest prawie niemożliwa.