Co myślicie o podpowiedziach w wyjątkach?

0

Zauważyłem, że niektóre biblioteki lub frameworki, ostatnio umieszczają podpowiedzi w wyjątkach. Ma to swoje wady i zalety.

Dla początkujących, które popełniają przewidywalne błędy, takie podpowiedzi mogą być dla niego pomocne, oszczędzić minuty/godziny google'ania, i zaśmiecania forum z 100x tym samym tematem.

Dla zaawansowanych, którzy nie popełniają takich przewidywalnych błędów, takie podpowiedzi mogą prowadzić w błąd lub być po prostu błędnym guessem.

Tutaj przykład takiego wyjątku bez podpowiedzi:

InvalidArgumentException : Negative limit: -2
 C:\Users\Riddle\PhpstormProjects\T-Regx\src\CleanRegex\Replaced\ReplacedImpl.php:44
 C:\Users\Riddle\PhpstormProjects\T-Regx\test\Feature\CleanRegex\Replaced\limits\Test.php:216

Tutaj przykład z podpowiedzią

InvalidArgumentException : Negative limit: -2, to remove limit use all() instead of only(int)
 C:\Users\Riddle\PhpstormProjects\T-Regx\src\CleanRegex\Replaced\ReplacedImpl.php:44
 C:\Users\Riddle\PhpstormProjects\T-Regx\test\Feature\CleanRegex\Replaced\limits\Test.php:216

Innym przykładem mogą być wyjątki z Django, np przy wyjątakach o nieistniejącym module, jest podpowiedź perhaps forgot to include settings?, przy exceptionie.

Jakie są wasze opinie nt temat?

2

Ja tam w wyjatkach czasem daje podpowiedzi ale to musi byc w miare trafny guess albo taki ktory nie zaszkodzi.

Jak nie ma glownego powodu to daje tylko info kontekstowe (np nr klienta).

2

@TomRiddle

Nie widzę wad, a jedynie zalety.

edit. albo ok, może czasami osoba pisząca musi się trochę postarać aby precyzyjnie wychwycić co poszło nie tak, ale nadal chyba warto?

może jak wyjaśnisz to w wyjątku, to ludzie mniej issues będą Ci zakładać lub nie będziesz musiał odpowiadać na pytania na Stacku dot. twojej libki = zaoszczędzony twój czas, a to na pewno duży + jeżeli chodzi o side projecty ;)

Dla zaawansowanych, którzy nie popełniają takich przewidywalnych błędów, takie podpowiedzi mogą prowadzić w błąd lub być po prostu błędnym guessem.

No to może rzucający wyjątek powinien się bardziej postarać?

3

Nie mam nic przeciwko podpowiedziom w wyjątkach jeśli faktycznie są trafne. Sam czasem dodaję podpowiedzi do wyjątków, ale w sumie rzadko. Częściej po prostu pakuję dużo kontekstowych informacji do opisu błędu i wtedy ktoś kto przegląda logi (np. ja sam) będzie miał większą szansę samemu wywnioskować źródło problemu. Czyli w sumie chyba podobnie co @vpiotr

0

I tak i nie. W idealnej sytuacji wyjątki służą do komunikowania nieprzewidzianych problemów.

Pytanie jest trochę analogiczne do "Czy dodawać komentarze do kodu?".

  • Jeśli rzucasz wyjątkami na prawo i lewo dla przypadków przewidywalnych błędów to TAK, dodawaj podpowiedzi
  • Jeśli kod jest nieczytelny to TAK, komentuj.

  • Jeżeli używasz innych konstrukcji językowych* do informowania o przewidywalnych błędach to NIE dawaj podpowiedzi (nie ma wyjątku, więc ciężko o podpowiedź :P)
  • Jeżeli kod jest czytelny to NIE komentuj

* - Mam na myśli wszelakie Eithery, Resulty, Tuple (result, error) - Z tym niestety jest taki problem, że nawet bardzo cywilizowane języki nie mają ich wbudowanych w stdlib/składnię, więc pisząc bibliotekę raczej nie dodamy (często dosyć sporej) zależności, więc zostają wyjątki lub lepsze projekty API, żeby nie dało się wejść w niepoprawny stan tam, gdzie to łatwe do uniknięcia lub zwracać odpowiedni obiekt reprezentujący faktycznie "success or errors".

W realnym świecie jednak wyjątki latają wszędzie gdzie to tylko możliwe, więc dodatkowe podpowiedzi o ile informatywne i trafne są zawsze w cenie.

1

@Grzyboo: zasadniczo masz rację, ale:

  1. To zadziała jedynie jeśli te eithery/resulty są wbudowane w język, albo w danej technologii istnieją dwie takie bibloteki (jedna dla community, druga dla trzech hipsterów, którzy zrobią wszystko, żeby być inni). Bo jeśli tak każda biblioteka/framework będzie definiowała swoje eithery/resulty, to zrobi się jakieś piekło dziwnych zależności i mapowań jednych na drugie. W takiej sytuacji, ja już wolę, gdy twórca rzuci wyjątek z opisem.
  2. W 98% przypadków te wyjątki nie będą widoczne na produkcji w ogóle, jedynie na etapie developmentu i będą spowodowane moim błędami konfiguracji/użycia danej biblioteki.
2

Jeżeli używasz innych konstrukcji językowych* do informowania o przewidywalnych błędach to NIE dawaj podpowiedzi (nie ma wyjątku, więc ciężko o podpowiedź :P)

To że coś jest przewidywalne nie powoduje że nie nadaje się na wyjątek. Twórcy connectora do BD może przewidzieć podanie złych danych uwierzytelniających, ale zwracanie jakiegoś Option<Connection> jest raczej... głupie, przynamniej moim zdaniem.

0

To jest chyba taka ogólna tendencja, np. jedną z przewag clanga nad gcc jest lepszy error reporting.

Clang has much better error reporting. 
E.g. if you make a typo in a function name you call, Clang will report that this is likely a typo (and suggest the correct name),
while GCC will complain about unknown function name.

https://softwareengineering.stackexchange.com/questions/70596/gcc-vs-clang-llvm-pros-and-cons-of-each#70598

Linia poleceń Linuxa w tej chwili też sama proponuje użycie apt jeśli dany program nie jest zainstalowany.

3

Zdecydowanie jestem za podawaniem podpowiedzi i jak najwięcej kontekstowej informacji w wyjątku w projektach, w których wyjątki służą do komunikacji błędów które może napotkać użytkownik.

Trzeba tylko uważać na podawanie wrażliwych danych (np hasła, tokeny) - tego w wyjątku bym nie umieszczał, bo nie ma potem pewności gdzie logi trafią i kto będzie miał dostęp (w ogóle rada dotyczy całego logowania).

Wv wątku mamy tu również ortogonalny problem czy w ogóle używać wyjątków do sygnalizacji błędów. No i tu odpowiedź zależy od języka i tak jak się w nim przyjęło i jakie mechanizmy mamy dostępne. Jeśli mamy sensowne try/result/either to użycie wyjątków powinno ograniczać się wyłącznie do błędów programisty - tj sytuacji których w poprawnym kodzie nigdy nie będzie i których zawsze można uniknąć - wyjście poza zakres tablicy, dereferencja nulla, dzielenie przez zero.
Problemy środowiska, które kontroluje użytkownik np. brak możliwości połączenia się z bazą, niepoprawne dane w pliku konfiguracyjnym czy zły parametr w linii poleceń powinny być sygnalizowane przez rezultat niosący informacje o błędzie, z minimum informacji technicznych (np. po co komu stacktrace) a maksimum wskazówek dla użytkownika, które możemy ładnie sformatowac na ekranie - stąd np. wymaganie w Rust, że Error musi implementować Display.

Niestety bardzo często widzę, zwłaszcza w aplikacjach z kulturą używania wyjątków do wszystkiego (m.in. Python, Java), że aplikacja daje stacktracem na każdy nawet najbardziej typowy błąd użytkownika. Brak połączenia z bazą - no to jakiś szczątkowy komunikat typu Can't connect i dwa ekrany stacktrace, ale często nawet brak informacji kontekstowej o adresie serwera, kodzie błędu zwróconego z OSa/bazy oraz wszelkich parametrach połączenia. I wtedy jak widzę coś takiego to dobrze że pracuje zdalnie, bo najgorsze co mogę zrobić to kogoś tylko op... grzecznie zwrócić komuś uwagę ;)

Ogólnie jako użytkownik bardzo lubię jak dostaje dodatkowe podpowiedzi w komunikacie błędu. Wzorem jest chyba kompilator Rusta, który czasami nawet sugeruje konkretne poprawki do kodu i nie dotyczy to tylko literówek (rzeczy w stylu - tej metody nie ma w bieżącym zasięgu, ale może chciałeś ja zaimportować stąd lub stąd?)

W ogóle dochodzę coraz bardziej do wniosku że dobrego programistę poznaje się po tym jak obsługuje błędy i jak pisze dokumentację do swojego kodu. Bo jakoś działający kod to w sumie każdy umie napisać.

3

Jeśli się robi bibliotekę to zdecydowanie. Sensowne informacje o błędach to część ergonomii.

Tylko nie da się tego zrobić łatwo - aby podawać pomocne informację potrzebny jest zwykle jakiś feedback od użytkowników, inaczej może być trudno zgadnąć co jest sensowną podpowiedzią w danym przypadku.

Obsługa błędów to to co zwykle wyróżnia dojrzały produkt od hipsterskiego kodu napisanego na kolanie.

Weźmy taką bazę danych Oracle, jak dostajesz:
ORA-00942 table or view does not exist

To Oracle nie powie Ci jak tabela - domyśl się. Co więcej komunikat ten wcale nie musi oznaczać, że tabela czy widok nie istnieje, równie dobrze może istnieć i przyczyną błędu jest coś innego: domyśl się. Najbardziej podoba mi się ten numerek 00942 - od razu pomaga wiedzieć, że to 00942, a nie np. 00941.

(Ale oracle wraz Sunem i Javą kupił też MySQL więc mają już w swoim portfolio jakąś bazę, która nie jest totalnie amatorska).

0
TomRiddle napisał(a):

Dla zaawansowanych, którzy nie popełniają takich przewidywalnych błędów, takie podpowiedzi mogą prowadzić w błąd lub być po prostu błędnym guessem.

Jak to było? Korzyści przeważają nad ryzykiem.

Tak jak z autocomplete.

Autocomplete w edytorach bardzo często (przez większość czasu?) podpowiada kompletnie nieadekwatne rzeczy, a mimo to jest pożyteczne, bo ten mały procent trafnych podpowiedzi może się i tak przydać i ułatwić pisanie programów, jeśli zapomnimy nazwy jakiejś metody czy argumentów.

Królik napisał(a):

Ogólnie jako użytkownik bardzo lubię jak dostaje dodatkowe podpowiedzi w komunikacie błędu. Wzorem jest chyba kompilator Rusta, który czasami nawet sugeruje konkretne poprawki do kodu i nie dotyczy to tylko literówek (rzeczy w stylu - tej metody nie ma w bieżącym zasięgu, ale może chciałeś ja zaimportować stąd lub stąd?)

Mnie się bardzo podoba to, że w Rust kompilator jeszcze na etapie kompilacji rzuca błędem i mówi, jak można zlikwidować ten błąd. Można się uczyć języka pisząc błędnie i sprawdzając feedback z kompilatora. Kompilator edukuje.

Z frameworków to kojarzę, że błędy w React też potrafią być wyjaśniające, co też od razu naprowadzi na rozwiązanie (jeśli problemem jest proste machnięcie się czy niedopatrzenie). I to też pokazuje profesjonalizm twórców tego frameworka, że dbają o użytkowników i przewidują błędy, jakie ktoś może popełnić.

0

Podpowiedzi w wyjątkach mają tę wadę, że o ile w miejscu rzucenia tego wyjątku wiadomo co się zrypało, to raczej nie koniecznie wiadomo dlaczego. Efektywna informacja o tym "co" jest dobra, pisanie "dlaczego" już niekoniecznie, bo to zwykłe zgadywanie.

Przykład z dzisiaj coś tam nie działa, dostaję pytanie co mogło pójść nie tak i log, gdzie w pierwszej linijce jest:
"something something, please restart the application"

  • restartowałeś aplikację?
  • ...
  • pomogło?
  • tak

Zwyczajnie kolega uznał, że komunikaty o tym co należy zrobić, są zwykle na tyle bez sensu, że zwyczajnie olał zastanawianie się, czy akurat w tym przypadku może mówią prawdę.

1

Jak najbardziej tak. Zwłaszcza na styku kod-infra, gdzie wręcz spodziewane jest, że ktoś źle coś skonfiguruje za pierwszym razem.

// jakiś kod na starcie aplikacji
if(!testReadingFromS3()) {
  throw new RuntimeException("An error occured when trying to list S3 bucket <name> using user <iam_role>. Please make sure that AWS_* variables are configured properly per README and it is possible to list and read objects in the bucket <bucket_name> using the supplied credentials");
}
3

Off-Top:

Pod wpływem tego wątku poprawiłem dziś sobie komfort pracy - okazało się, że kompilator https://dhall-lang.org/ ma dodatkowy parametr --explain i czasem daje on jakieś sensowne wskazówki (bo standardowe komunikaty z kompilatora dhall to chyba ideał nieprzydatności).

1

Ogólnie nie lubię tego typu podpowiedzi, lubię diagnostykę. Tj. "InvalidArgumentException: parameter MyParameter can't be negative" jest spoko, ale takie zgadywanki na zasadzie "sprawdź X, Y i Z" są słabe. Lepiej wypisać to co ważne, czyli wejście i ewentualny stan do którego odwołuje się funkcja.

Wyjątkiem są oczywiście sytuacje, gdy wiadomo o co chodzi.

1 użytkowników online, w tym zalogowanych: 0, gości: 1