Temat: SOLIDny kod
Osobiście stosuję od wielu lat zasady następujące:
1. To, co mogę przewidzieć i sprawdzić (np. czy plik istnieje), sprawdzam "ręcznie", bez użycia wyjątków. Stosuję do tego celu metody (walidatory) z utworzonych wcześniej statycznych klas pomocniczych. W praktyce oznacza to, że takie klasy mogę sobie traktować jako swoistą "bibliotekę" i wykorzystywać je w tych projektach, w których ich potrzebuję. Ważne jest to, że metody-validatory z definicji nie rzucają wyjątków same z siebie. Zwykle zwracają bool, ewentualnie jakiś enum. W tych validatorach staram się także nie używać wyjątków.
2. Bardziej upierdliwe rzeczy, jak np. obsługa przypadku, gdy plik XML jest uszkodzony i ma zły format (mowa o formacie "fizycznym" - czyli np. sparowaniach i domknięciach tagów, a nie logicznym, czyli czy oczekiwany tag w pliku istnieje), obsługuję również w podobny sposób, ale tutaj już wewnątrz validatora zwykle stosuję wyjątki: chodzi raczej o pracochłonność - np. "ręczne" sprawdzenie formalnej poprawności pliku XML jest potwornie upierdliwe i nikt nie namówiłby mnie chyba do tego, żeby zrobić parser sprawdzający format XML-a. Oczywiście wyjątek NIGDY nie wydostaje się na zewnątrz validatora - validator zwraca bool lub enum. Dotyczy to również podsystemu FileIO - absurdem dla mnie jest obsługiwanie wyjątkiem w logice aplikacji przypadku, kiedy np. użytkownik podał (wklepał) w formatce nieprawidłową (formalnie) nazwę pliku. To jest błąd dający się przewidzieć, o dużym prawdopodobieństwie wystąpienia, i obsługiwany powinien być przez validator.
3. Prawie każda metoda w moim kodzie sprawdza z definicji poprawność otrzymanych parametrów - mam na myśli poprawność formalną, ale z punktu widzenia aplikacji. Np. jeśli metoda ma zrobić lookup na bazie danych wyszukujący usera po loginie, ZAWSZE sprawdzam czy login nie jest pusty. Albo, jeśli metoda ma dostać jako parametr instancję obiektu DTO, sprawdzam, czy nie jest ona równa null. Zwykle niepowodzenia takiego sprawdzania loguję do pliku logu ze wskazaniem metody (i klasy), w której to wyłapałem. Co więcej, nie boję się sprawdzać tego samego w różnych miejscach (np, przy zagnieżdżeniu wywołań kolejnych metod) - niby nadmiarowy kod, ale doskonale ratuje dupę i oszczędza nasz czas w tych przypadkach, kiedy to my popełnimy błąd w czasie kodowania.
3. Wyjątki stosuję jawnie i "publicznie" wszędzie tam i tylko tam, gdzie może wystąpić błąd nieprzewidywalny i całkowicie niezależny (typu brak zasobów, błąd aplikacji) - czyli w praktyce w bardzo niewielu miejscach. Po prostu wyjątków używam do obsługi sytuacji naprawdę wyjątkowych i nieprzewidywalnych.
4. Jeśli już stosuję wyjątki, staram się obsługiwać je najwcześniej, jak się da (czyli w praktyce zwykle w tej samej jeszcze metodzie, w której wyjątek wystąpił), no i oczywiście wszystkie loguję do pliku logu. Dodatkowo w takich sytuacjach często loguję wartość kluczowych zmiennych czy parametrów metody. A użytkownik dostaje jedynie informację, że określona rzecz się nie powiodła - natomiast nigdy nie pokazuję mu stack trace,a - to jest informacja dla mnie, a nie dla niego. Jedyne, co użytkownik ma ewentualnie zrobić, to przesłać mi mailem plik logu.
Te zasady bardzo dobrze się u mnie sprawdziły, ewentualne błędy mogę poprawiać zwykle jednym strzałem (mam plik logu, więc wiem co i gdzie się powaliło) - nawet, jeśli aplikacja już pracuje u endusera.
Owszem, konsekwentne stosowanie tych zasad oznacza jakieś 10...15% więcej roboty przy kodowaniu, ale to się zwraca z nawiązką podczas wdrożenia i podczas trwania okresu gwarancyjnego - czyli w tych sytuacjach, kiedy muszę pracować szybko, poza harmonogramami, no i w pewnym sensie "za darmo" (gwarancja - a kasa dawno "zjedzona").
Ten post został edytowany przez Autora dnia 04.05.14 o godzinie 17:34