Przejdź do treści

DevStyle - Strona Główna
Custom exceptions
Backend

Kiedyś na stronach MS widziałem rekomendację mówiącą “używaj typów wyjątków dostarczanych przez framework“. Jakiś czas temu, na jakimś polskim chyba blogu, przeczytałem tego powtórkę. Wiecie co? U mnie się doskonale sprawdza kompletne przeciwieństwo tej praktyki.

Wyjątek bazowy

Zawsze w swoich aplikacjach staram się mieć jeden bazowy typ wyjątku, abstrakcyjna klasa MyAppException: Exception. Dzięki temu jestem w stanie wyłapać wszystko co rzuca mój kod, a nie jakieś flaki pod spodem. Wyjątki, które ja rzucam, będą charakterystyczne dla mojego systemu, więc będą to, jak je czasami nazywam, “wyjątki biznesowe“.

Co mi to daje? A chociażby to, że łapiąc taki wyjątek mogę zalogować wszystko co mi potrzebne, ale użytkownikowi wyświetlić taki komunikat jaki będzie dla niego zrozumiały.

I…

Dodatkowo czasem doprowadzam swoją wyjątkową praktykę do ekstremum i staram się, aby każdy wyjątek był rzucany tylko raz. Potraficie sobie to wyobrazić? Ile musi być tych klas wyjątków? Ano w tak zwaną pytę. I dobrze, dokładnie o to mi chodzi. Nie muszę wysilać się na jakieś wiele mówiące exception message. CO się stało – powie mi sam typ wyjątku. A towarzyszące temu okoliczności – czyli aktualne dane w tym obszarze systemu – przyjmowane są jako parametry konstruktora.

Na ich podstawie kleję najprostszego możliwego stringa, który wyląduje w logach. Użytkownik tego i tak nie zobaczy, bo… patrzcie wcześniej – typ wyjątku jest zmapowany na komunikat (w resx) wyświetlany użytkownikowi.

Te korzyści same w sobie są jak dla mnie wystarczające, ale to nie wszystko! Ile razy w testach sprawdzaliście, czy treść wyjątku zawiera jakieś odpowiednie informacje żeby upewnić się, że wyjątek leci z oczekiwanej ścieżki kodu? Z takiego InvalidOperationException niewiele poza tym można wyciągnąć. Moje testy znacznie się uprościły od kiedy stosuję opisywane podejście. Sprawdzam po prostu czy w odpowiednich okolicznościach leci odpowiedni typ wyjątku, to tyle.

A przykład z życia? Proszę bardzo!

Życie – dialer

Przed kilka miesięcy pracowałem nad “dialerem” – aplikacją do dzwonienia do ludzi i wciskaniu im produktów (z czegoś podobnego korzysta ten cholerny telemarketer, który w piątek wieczorem dzwoni do was z banku i próbuje przekonać że naprawdę potrzebujecie kolejnej karty kredytowej). A oto przykładowa hierarchia wyjątków (btw, chyba żadna inna część aplikacji nie ma tak rozbudowanego dziedziczenia:) ):

Najpierw mamy “abstract MyDialerException“. Potem wyjątek bazowy dla scenariusza “wykonywania połączenia”: “abstract DialingException: MyDialerException“. A poniżej już konkretne wyjątki, opisujące co poszło nie tak: CallAlreadyInProgressException : DialingException, IncorrectNumberException: DialingException, NumberAlreadyDialedException: DialingException… i jeszcze parę.

Jak ktoś zapyta “co w twoim systemie może pójść nie tak?” to wystarczy, że pokażę klasy dziedziczące z MyDialerException – i wszystko jasne.

Pozamiatane.

Zobacz również