... o których każdy programista
wiedzieć powinien.

Zawsze słuchaj ekspertów. Oni powiedzą ci, czego nie da się zrobić i dlaczego. A ty potem to zrób.
-- Robert Heinlein
Pete Goodliffe

Nie ignoruj tego błędu!

Oryginalny tytuł: Don't Ignore that Error!

Autor: Pete Goodliffe

Szedłem ulicą wieczorem na spotkanie z przyjaciółmi w barze. Nie piliśmy wspólnie piwa od jakiegoś czasu. Nie mogłem się doczekać, by się z nimi zobaczyć. W moim pośpiechu nie patrzyłem gdzie stąpam. Potknąłem się na krawężniku i przewróciłem się na twarz. Cóż... Zgaduję, że przysługuje mi prawo do nie zwracania uwagi.

Zraniłem się w nogę, ale dalej spieszyłem się na spotkanie z przyjaciółmi. Wstałem i poszedłem dalej. Idąc dalej, ból stawał się coraz gorszy. Chociaż nagle zrozumiałem, że coś było nie tak.

Pomimo to, spieszyłem do baru. Byłem w agonii, kiedy tam dotarłem. Nie miałem fajnego wieczoru, ponieważ byłem strasznie rozproszony. Nad ranem poszedłem do lekarza i okazało się, że złamałem nogę. Gdybym zatrzymał się, gdy poczułem ból, ograniczyłbym dalsze urazy, które spowodowałem, idąc na niej. To był prawdopodobnie najgorszy poranek po imprezie w moim życiu.

Zbyt wielu programistów pisze kod w sposób, który przypomina mój katastrofalny wieczór.

Błąd, jaki błąd? Nie będzie poważny. Na pewno. Mogę go zignorować. To nie jest strategia, która prowadzi do solidnego kodu. Tak naprawdę to czyste lenistwo. Nieważne, czy uważasz, że błąd w kodzie jest mało prawdopodobny, powinieneś zawsze się go spodziewać i obsłużyć. Zawsze. Nie oszczędzasz czasu, jeśli tego nie robisz. Odkładasz potencjalne problemy na później.

Raportujemy błędy w naszym kodzie na kilka sposobów:

  • Kody powrotu (ang. return codes) mogą być użyte do przekazania, że "coś nie zadziałało". Błędy sygnalizowane w kodach powrotu są aż za łatwe do zignorowania. Nie zobaczysz nic w kodzie, co mogłoby podkreślić problem. Rzeczywiście, stało się to standardową praktyką, by ignorować kody powrotu pewnych standardowych funkcji języka C. Jak często sprawdzasz kod powrotu funkcji printf?
  • errno jest ciekawym smaczkiem języka C, osobną zmienną globalną ustawioną na sygnał błędu. Jest łatwa do zignorowania, ciężka do użycia i prowadzi do wszelkiego rodzaju nieprzyjemnych problemów - na przykład, co się stanie, kiedy wiele wątków wywoła tę samą funkcję? Niektóre platformy ograniczają Ci bólu w takiej sytuacji, inne nie.
  • Wyjątki (ang. exceptions) są bardziej ustrukturalizowanym, wspieranym przez język programowania sposobem sygnalizowania i obsługi błędnych sytuacji. Nie możesz ich zignorować. A może możesz? Widziałem wiele kodu jak ten poniżej:
    
      try {
        // ... zrób coś ...
      }
      catch (...) {} // zignoruj błędy

Zbawienną łaską tej okropnej konstrukcji jest to, że podkreśla ona fakt robienia czegoś moralnie wątpliwego.

Jeśli ignorujesz błąd, przymykasz oko i udajesz, że nic się nie stało, podejmujesz wielkie ryzyko. Tak jak moja noga, która skończyła w gorszym stanie, niż jeśli bym zatrzymał się od razu, robienie czegoś na siłę może prowadzić do bardzo skomplikowanych awarii. Zmierz się z problemami przy pierwszej nadarzającej się okazji. Prowadź krótki rachunek.

Nieobsługiwanie błędów prowadzi do:

  • Wątłego kodu (ang. brittle code). Kodu przepełnionego ekscytującymi, ciężkimi do znalezienia błędami.
  • Niebezpiecznego kodu. Krakerzy czesto wykorzystują słabą obsługę błędów, by włamać się do systemu komputerowego.
  • Słabej struktury. Jeśli są błędy z Twojego kodu, których obsługa jest nudna, prawdopodobnie masz słaby interfejs. Wyraź je tak, aby błędy były mniej inwazyjne a ich obsługa mniej uciążliwa.

Tak jak zawsze powinieneś sprawdzać wszyskie potencjalne błędy w swoim kodzie, tak potrzebujesz wyeksponować wszystkie potencjalne sytuacje w swoich interfejsach, które mogą prowadzić do błędów. Nie chowaj ich, udawając, że Twoje usługi zawsze będą działać.

Czemu nie sprawdzamy, czy wystąpiły błędy? Jest kilka popularnych wymówek. Z którymi z poniższych się zgadzasz? Z którymi nie i dlaczego?

  • Obługa błędów zaciemnia przepływ wykonania programu, utrudnia czytanie i wykrycie "normalnego" przepływu wykonania.
  • To dodatkowa praca a właśnie zbliża się termin zakończenia projektu.
  • Wiem, że ta funkcja nigdy nie zwraca błędu (printf zawsze działa, malloc zawsze zwraca nową pamięć i tak dalej).
  • To jest tylko program pisany dla zabawy i nie ma potrzeby dbania o jakość kodu.
Creative Commons Uznanie Autorstwa 3.0 Artykuł został opublikowany na licencji Creative Commons Uznanie Autorstwa 3.0.
Tłumaczenie: Marcin

Komentarze (2)

Lasu pisze:
04-07-2011 17:12:28
Ave, Obsługa wyjątów to pożyteczna sprawa - ale czasami przepakowana - przez co ludzie się zniechęcają. Nie mówiąc już o sytuacji, w której późniejszy wyjątek powoduje zniknięcie pierwszego (Java: try+finally). Dlatego też chętnie zobaczył bym takie zmiany jak: http://lasu2string.blogspot.com/2010/02/forwarding-as-language.html Pozdrowionka.
Joe pisze:
07-07-2011 10:30:14
"Nieważne, czy uważasz, że błąd w kodzie jest mało prawdopodobny, powinieneś zawsze się go spodziewać i obsłużyć. Zawsze." Ładnie brzmi, ba nawet mnie poruszyło, ale takie postępowanie jest chore, jeśli obstawi się klauzulą try..catch, każdą dynamiczną alokację w C++.

Dodaj komentarz

*
 
 
*
*