Polecam wzorzec projektowy / podejście do ujawniania / tolerowania / odzyskiwania po błędach systemowych, obsługę wyjątków (np. W Javie, C ++, Perlu, PHP)

13

Czy możesz polecić wzorzec / podejście projektowe do ujawniania / tolerowania / odzyskiwania po błędach systemowych, obsługi wyjątków (Java, C ++, Perl, PHP)?

Niektóre błędy muszą zostać zgłoszone.

Niektóre błędy mogą być obsługiwane wewnętrznie (przez ponowienie lub są nieistotne (można je zignorować).

Jak ustrukturyzować kod, aby je złapać?

Ale wszystkie błędy muszą być rejestrowane.

Jakie są najlepsze praktyki?

A czy symulować je, aby móc w pełni przetestować komponenty, na które mają wpływ?

Ogólne pytanie specyficzne dla języka nieprogramowego mające zastosowanie do kilku współczesnych języków programowania, ale mile widziane byłyby przykłady ilustracji wzorców, podejść i filozofii w Javie, C ++, PHP i Perlu.

(Pytanie Również w stackoverflow: /programming/7432596/recommend-a-design-pattern-approach-to-exposing-tolerating-recovering-from-system ale myślałem, że powinien on zostać poproszony o programistów, ponieważ zbyt Myślę, że programiści zadają pytania dotyczące szerszych zagadnień związanych z oprogramowaniem / programowaniem, podczas gdy przepełnienie stosu dotyczy bardziej technicznej implementacji IMHO).

therobyouknow
źródło
2
Dla mnie twoje pytanie wydaje się zbyt ogólne i otwarte, aby można było na nie skutecznie odpowiedzieć. Spróbuj ograniczyć go do niektórych bardziej szczegółowych przypadków, a także do określonych typów aplikacji / środowisk (np. Aplikacja / serwer GUI / ...).
Péter Török,
Zobacz także stackoverflow.com/questions/937285/…
Péter Török
@ Péter Török, mikera zapewnia dobrą odpowiedź, która może zaakceptować ich odpowiedź.
therobyouknow,

Odpowiedzi:

16

Fail fast to świetne podejście do projektowania i być może można je uznać za wzór: http://en.wikipedia.org/wiki/Fail-fast

Znalazłem również szereg zasad, które mogą się przydać:

  • Rozważ wyjątki jako część interfejsu do każdej funkcji / modułów - tj. Udokumentuj je i tam, gdzie to właściwe / jeśli twój język to obsługuje, użyj sprawdzonych wyjątków.
  • Nigdy nie krępuj niepowodzenia - jeśli to się nie powiedzie, nie próbuj kontynuować, próbując „założyć”, jak postępować. Na przykład, specjalna obsługa przypadków null jest dla mnie często zapachem kodu: jeśli twoja metoda potrzebuje wartości innej niż null, powinna natychmiast zgłosić wyjątek, jeśli napotka null (albo NullPointerException lub idealnie bardziej opisowy IllegalArgumentException).
  • Napisz testy jednostkowe dla wyjątkowych i normalnych przypadków - czasem takie testy mogą być trudne do skonfigurowania, ale warto, jeśli chcesz mieć pewność, że twój system jest odporny na awarie
  • Zaloguj się w punkcie, w którym błąd został wychwycony i obsłużony (zakładając, że błąd miał wystarczającą istotność, aby zostać zarejestrowanym). Powodem tego jest to, że rozumiesz przyczynę i masz podejście do obsługi błędu, dzięki czemu możesz nadać komunikatowi logicznemu sens ...
  • Używaj wyjątków tylko w przypadku naprawdę nieoczekiwanych warunków / awarii. Jeśli twoja funkcja „zawiedzie” w sposób, który jest rzeczywiście oczekiwany (np. Odpytywanie w celu sprawdzenia, czy dostępnych jest więcej danych wejściowych i nie znalezienie żadnego), powinno zwrócić normalną odpowiedź („brak dostępnych danych wejściowych”), a nie zgłaszać wyjątku
  • Z gracją zawdzięczamy (podziękowania dla Stevena Lowe!) - posprzątaj przed zakończeniem, jeśli to w ogóle możliwe, zazwyczaj przez cofnięcie zmian, wycofanie transakcji lub zwolnienie zasobów w wyciągu „w końcu” lub równoważnym. Oczyszczanie powinno idealnie odbywać się na tym samym poziomie, na którym zasoby zostały przeznaczone dla zachowania jasności i logicznej spójności.
  • Jeśli musisz zawieść, zawiedź głośno - wyjątek, że żadna część twojego kodu nie była w stanie obsłużyć (tj. Perkolować na najwyższy poziom bez przechwycenia + obsługi), powinna spowodować natychmiastową, głośną i widoczną awarię, która skieruje na to twoją uwagę. Zazwyczaj zatrzymuję program lub zadanie i piszę pełny raport wyjątków do System.out.
mikera
źródło
1
również z wdziękiem zawodzą - posprzątaj przed zakończeniem, jeśli to w ogóle możliwe
Steven A. Lowe
+1 @ mikera za jasne punkty na temat tego, co należy wziąć pod uwagę. Prawdopodobnie przyjęta odpowiedź, pozostawiam otwartą na dłużej, aby inni mogli się w nią wesprzeć.
therobyouknow,
+1 @ Steve A. Lowe - dla projektu zorientowanego na użytkownika. np. zapisywanie plików, nie pozostawianie plików tymczasowych. Zobacz moje pytanie dotyczące „higieny danych” jako pokrewny temat na mojej liście pytań.
therobyouknow,
5

Po pracy z wyjątkami w Javie i .NET ORAZ po przeczytaniu wielu artykułów o tym, jak / kiedy / dlaczego łapać wyjątki, w końcu wymyśliłem następujące kroki, które przechodzę w mojej głowie, gdy widzę potencjalny wyjątek lub wyjątek Muszę złapać (Java) ... nawet jeśli to się nigdy nie zdarzy (westchnienie ...). I wydaje się, że działa, przynajmniej dla mnie:

  1. Czy jest coś przydatnego, co mogę zrobić z tym wyjątkiem (oprócz rejestrowania)? Jeśli odpowiedź brzmi tak, napisz kod obejścia, a jeśli obejście może powodować wyjątki, przejdź do 2:
  2. Owiń wyjątek wokół wyjątku środowiska wykonawczego, wyrzuć go, przejdź do 3.
  3. W klasie wyższego poziomu, w której zainicjowano możliwą transakcję bazy danych / procesu, złap wyjątek, wycofaj transakcję, zwróć wyjątek.
  4. W klasie najwyższego poziomu (która może być tą, w której transakcja została zainicjowana) zaloguj wyjątek za pomocą środowiska rejestrowania, takiego jak slf4j ( na przykład w połączeniu z log4j ) lub log4net . Jeśli to możliwe, wyślij e-mailem wyjątek bezpośrednio na listę dystrybucyjną złożoną z programistów aplikacji.
  5. Jeśli istnieje GUI, wyświetl komunikat o błędzie wskazujący w najbardziej przyjazny dla użytkownika sposób, co spowodowało problem; nie wyświetlaj wyjątku / stacktrace, użytkownik nie dba o to i nie musi wiedzieć, że był to wyjątek NullPointerException.

Powinienem również dodać krok 0 , w którym celowo rzucam coś, co nazywam wyjątkiem „biznesowym” (nowy wyjątek, który tworzę, rozszerzając klasę „wyjątek”), gdy niektóre złożone leczenie nie może zostać wykonane z powodu błędów danych, ALE zdarzają się, ponieważ podczas analizy zostały zidentyfikowane jako przypadki wyjątków.

Z wyjątkiem części dotyczącej logowania, w pełni zgadzam się z punktami napisanymi przez „mikera”; Dodam tylko, że wyjątek należy zarejestrować tylko raz .

Ponadto wymienione przeze mnie kroki mogą się różnić, jeśli piszesz jako API / Framework . Tam rzucanie dobrze zaprojektowanych wyjątków jest obowiązkowe, aby pomóc programistom zrozumieć ich błędy.

Jeśli chodzi o testowanie wyjątków, za pomocą próbnych obiektów powinieneś być w stanie przetestować prawie wszystko, niezależnie od tego, czy jest to wyjątek, czy nie, pod warunkiem, że twoje klasy przestrzegają najlepszej praktyki „jedna klasa do robienia jednej rzeczy”. Osobiście upewniam się, że najważniejsze, ale ukryte metody są oznaczone jako „chronione” zamiast „prywatne”, dzięki czemu mogę je przetestować bez większych problemów. Poza tym testowanie wyjątków jest proste, po prostu sprowokuj wyjątek i „spodziewaj się”, że wyjątek wystąpi, wychwytując go. Jeśli nie otrzymasz wyjątku, oznacza to, że wystąpił błąd przypadku testowego jednostki.

Jalayn
źródło
+1 @Jalayn za wzmiankę o log4j, to jest to, czego używam, więc wzmacnia to, aby wiedzieć, że ktoś też jest.
therobyouknow,
0

Zbuduj swoje obiekty we właściwy sposób, nie martw się czynnikami zewnętrznymi. Jeśli zdecydujesz się skorzystać z wyjątków, spraw, aby Twoje obiekty zgłaszały wyjątki, jeśli coś się nie powiedzie .

Gdy wszystkie Twoje obiekty będą działać poprawnie, powinno być dość łatwo wymyślić przejrzystą hierarchię odpowiedzialności za błędy w projekcie.

Yam Marcovic
źródło