Reprezentowanie reguł biznesowych z wyjątkami

16

Wiem, że jest drogi, ale (IMO) uważam, że jest to bardzo dobra praktyka. Mówię o zasadach takich jak powiedz, że nie możesz zapisać faktury, jeśli nie jesteś sprzedawcą ... więc w takim przypadku zgłaszając wyjątek z informacją, że „nie masz autoryzacji” lub coś takiego…

Innym podejściem byłoby posiadanie obiektów o statusie lub coś w tym rodzaju

Czy jest jakieś inne podejście? jak się z tym czujesz?

sebagomez
źródło

Odpowiedzi:

15

Jeśli masz na myśli reprezentowanie pojedynczych kontroli reguł biznesowych z wyjątkami, nie sądzę, że to bardzo dobry pomysł. Wiele razy musisz zgłosić więcej niż jeden nieudany warunek i nie zatrzymywać się na pierwszym.

Z drugiej strony uważam, że sprawdzanie wszystkich reguł, a następnie zgłaszanie wyjątku z podsumowaniem, jest dobrą praktyką.

matiash
źródło
1
Właśnie tak sobie z tym radzę w moich aplikacjach. Korzystanie z FluentValidation, aby ułatwić mi życie, a metoda ValidateAndThrow oszczędza mój dzień.
Matteo Mosca
W aplikacji interfejsu użytkownika zgadzam się całkowicie, ale w aplikacji warstwy usług generowałbym wyjątek, jeśli przekazano mi obiekt niezgodny z regułami biznesowymi. Jeśli używasz tych dwóch w kombinacji, czasami dodajesz funkcję sprawdzania poprawności lub złożony błąd, jak opisuje to matiasha w ostatnim zdaniu.
Bill
8
Rzuć wyjątek specyficzny dla domeny . To pozwala ci rozdzielić nasze i nie-nasze wyżej.
@ Thorbjørn Ravn Andersen +1 świetny dodatek „specyficzny dla domeny”
Justin Ohms
1
@JamesPoulson może być wystarczające, aby utworzyć JamesPoulsonExceptionjako podklasę, RuntimeExceptiona następnie podać oryginalny wyjątek jako cause. Następnie możesz po prostu powiedzieć, if (exception instanceof JamesPoulsonException)... żeby różnicować. Użyj getCause()metody, aby osiągnąć oryginalny wyjątek.
9

W podanym przez ciebie przykładzie myślę, że zgłoszenie wyjątku jest złym pomysłem. Jeśli wiesz, że użytkownik nie jest autoryzowany przed rozpoczęciem pracy i nadal pozwalasz mu wykonać jakąś funkcję, a następnie uderzyć go komunikatem PO wykonaniu przez niego zadania, to po prostu zły projekt.

Stosowanie wyjątków w celu egzekwowania reguł biznesowych nie jest dobrym pomysłem.

Walter
źródło
Rozumiem, co powiedziałeś, że nie zgadzasz się z interfejsem użytkownika. Nie przeszkadza mi to. Zgadzam się z tobą, że o wiele bardziej przyjazny interfejs użytkownika nie pozwoli ci próbować zaktualizować czegoś, co nie jest dozwolone. Ale to nie znaczy, że sprawdzanie poprawności i wyjątków w rdzeniu biznesowym nie jest konieczne. Przeciwnie, uważam, że są koniecznością. Potrzebujesz ich, aby źle zaprogramowany interfejs użytkownika nie pozwalał na niewłaściwe użycie BL.
Fede
8
@Fede: chodzi o rozdzielenie obaw. Interfejs użytkownika jest odpowiedzialny za zbieranie intencji użytkownika i zgłaszanie informacji zwrotnych z warstwy biznesowej. Zadaniem warstwy biznesowej jest analizowanie informacji zebranych przez interfejs użytkownika, analizowanie ich i raportowanie z powrotem do interfejsu użytkownika i / lub proszenie warstwy danych o zachowanie niektórych danych. Między tymi warstwami powinno być tylko luźne połączenie. Wyjątek stanowią słabe, złe podejście do luźnego sprzęgania. Oznacza to nie tylko dzielenie rzeczywistych klas między warstwami, ale także wywołuje mechanizm, który ma obsługiwać nieoczekiwane awarie.
Adam Crossland
@Adam - Dobrze powiedziane i dokładnie na temat.
Walter
1
@Adam - Nie podążaj za tobą z rozdziałem problemów. Nie oczekuję, aby ktokolwiek w interfejsie obsługiwał CustomerNameInLowercaseException (proszę, mam również nadzieję, że wyjątek nawet nie istnieje!). Możesz po prostu obsłużyć ogólny ValidationException. Poza tym jestem w 100% z tobą, że interfejs powinien zbierać tylko informacje i całą resztę. Powiedziałem wcześniej, że bez względu na to, co robisz w interfejsie użytkownika, BL nie powinien zakładać, że każde wejście jest w porządku. To tylko programowanie obronne.
Fede
@ Fede: zadaniem warstwy biznesowej jest upewnienie się, że każde wejście jest OK. Jeśli robi to interfejs użytkownika, to implementuje logikę biznesową. Teraz, jeśli jest to przypadek, że pole wejściowe jest ograniczone do cyfr i znaków alfa BL widzi, by wszystkie środki rzucać się wyjątek . Ilekroć komponent odbiera nieprawidłowe dane wejściowe z innego komponentu, zgłaszanie wyjątku jest logiczne i słuszne. Interfejs został uszkodzony, a system uszkodzony. Jednak sprawdzanie poprawności danych wejściowych różni się bardzo od wykonywania logiki biznesowej. Dwie bardzo różne rzeczy.
Adam Crossland
5

Nie rozumiem, jaką wartość ma wyjątek w tworzeniu dobrej logiki biznesowej. Istnieją dziesiątki podejść do obsługi logiki biznesowej, które nie wymagają użycia systemu przeznaczonego do rozwiązywania nieoczekiwanych warunków w działaniu systemu.

Jest oczekiwać , że w logice biznesowej, nie zostaną spełnione warunki; to jest powód, dla którego to się dzieje, i nie chcesz piggyback na tym samym mechanizmie, który obsługuje nieoczekiwane awarie we / wy, błędy pamięci i odwołania zerowe. Są to awarie systemu, ale wykrycie niespełnionych warunków biznesowych jest pomyślnym działaniem systemu.

Ponadto jest to system dojrzały do ​​niezamierzonych konsekwencji. Ponieważ w pewnym momencie należy przechwycić wyjątek, istnieje ryzyko, że zostanie wykryty nowy wyjątek reguły biznesowej w miejscu, w którym nie jest on przeznaczony, lub istnieje szansa, że ​​kod wyszukujący reguły biznesowe wychwytuje wyjątki, które w rzeczywistości nie są przeznaczone dla tego. Tak, warunki te można wytłumaczyć dobrymi praktykami kodowania, ale w każdym nietrywialnym systemie, w którym pracuje więcej niż jeden programista, pojawią się błędy i trzeba mieć nadzieję, że nie będą to kosztowne błędy.

Adam Crossland
źródło
1
Zgadzam się, wyjątki nazywane są wyjątkami, ponieważ nie oczekuje się ich wystąpienia. Z drugiej strony, egzekwowanie reguł biznesowych w warstwie usług z wyjątkiem niekoniecznie jest złe. Nie oczekujesz, że zostanie on wykorzystany, oczekujesz, że klient będzie tylko wywoływał operacje i przekazywał tylko dane spełniające obowiązujące warunki; ale chcesz zbudować warstwę ochronną, ponieważ wiesz, że w kodowaniu klienta mogą również wystąpić błędy. Coś w rodzaju użycia ograniczeń klucza obcego w bazie danych: oczekujesz, że ludzie będą poprawnie wstawiać i aktualizować dane, ale wiedzą, że mogą zawieść z powodu błędu programowania.
Jeremy
2

Wyrażanie reguł biznesowych to jedno, wdrażanie ich to drugie

pomyśl o wrażeniach użytkowników; Jeśli użytkownik nie jest sprzedawca, dlaczego dać im przycisk z napisem „tworzyć fakturę” w ogóle ?

Steven A. Lowe
źródło
1
To, że nie dajesz przycisku, nie oznacza, że ​​i tak nie wyślą ci wiadomości. Pomyśl, jakie byłyby proste zasady bezpieczeństwa, gdyby to wszystko wystarczyło ...
jmoreno
Jeśli użytkownik nie może wykonać X, nie należy dawać mu przycisku z napisem „Do X”. Najlepszym zabezpieczeniem jest ignorancja - nie mów użytkownikowi o rzeczach, których nie może zrobić;)
Steven A. Lowe
1

To zależy całkowicie od tego, co zostało zrobione.

Po pierwsze, jakie rzeczywiste zachowanie chcesz? Jeśli ktoś wprowadza własne informacje, odrzucenie i okno dialogowe z napisem „Nie możesz tego zrobić” jest prawdopodobnie prawidłowe. Jeśli jest to osoba wprowadzająca dane, pracująca na stosie formularzy, okno dialogowe jest prawdopodobnie również dobre, a osoba wprowadzająca dane może umieścić nieprawidłowe formularze na specjalnym stosie. Jeśli wykonujesz przetwarzanie wsadowe, nie chcesz zatrzymywać rzeczy, ale oflaguj je i przejdź do następnego.

Kiedy już to zrobisz, musisz zdecydować, jak je wdrożyć. Sprawdzanie reguł biznesowych, które generuje wyjątek, jest prawdopodobnie dobrym pomysłem. Zwracanie kodu powrotu i przekazywanie go dalej jest czymś innym, co może pójść nie tak, a na pewno nie chcesz, aby błędne wpisy były dalej.

Nie martw się o koszty wydajności. W przypadku wprowadzania danych przez osobę jest to banalne w porównaniu z innymi czasami. Zazwyczaj człowiek zajmuje najwięcej czasu w tym systemie. W przypadku zadania wsadowego, jeśli wyjątki stanowią problem z wydajnością, wpisujesz o wiele za dużo złych rekordów, a w rzeczywistości ich obsługa i ponowne wprowadzanie będzie bardziej problematyczne niż wyjątki.

David Thornley
źródło
0

Posiadanie solidnego i dobrze zaprojektowanego API wyjątku, który jest spójny, jest bardzo odpowiednie. Wykorzystanie tego do egzekwowania reguł biznesowych może być również odpowiednie. W rzeczywistości z mojego doświadczenia wynika, że ​​im bardziej skomplikowana reguła biznesowa, tym większe prawdopodobieństwo, że zostanie w ten sposób potraktowana. Często jest tak samo łatwo, jeśli nie łatwiej, napisać system, w którym spodziewane są wyjątki, niż napisać autorytatywną logikę rozgałęziania.

Oznacza to, że proste reguły, które można opisać w jednym zdaniu, powinny być ogólnie stosowane w sposób zapobiegawczy lub autorytatywny, w zależności od tego, które są. Jeśli jednak masz regułę, która jest wielowymiarowa i wymaga więcej niż trzech lub czterech czynników (szczególnie jeśli wybór tych czynników jest oparty na jednym lub więcej innych czynników), kodowanie wyjątków może być łatwiejsze do utrzymania. Często w tych przypadkach ścieżka logiczna będzie zawierała wiele wyjątków prekursorów, które muszą zostać zgłoszone (sprawdza, dlaczego działanie nie może zostać wykonane), a następnie (lub odwrotnie) do bezpieczeństwa (aby sprawdzić, czy działanie jest autoryzowane) ), czasami będzie istniała pewna autorytatywna logika akumulacji, która musi zostać sprawdzona (dostępność potomka / przodka, prekursor stwierdza, że ​​obiekty muszą być umieszczone itp.)

Jedną z korzyści wynikających z tego typu zgłaszania wyjątków jest to, że pozwala oddzielić wyjątki od prekursorów i ponownie je wykorzystać w wielu obszarach projektu. (To jest istota programowania zorientowanego na aspekty.) Robiąc to, ujmujesz jeden szczególny aspekt twoich ogólnych reguł biznesowych w samodzielny i łatwy do utrzymania komponent. Zasadniczo te składniki będą odpowiadać 1-1 z wyświetlanymi komunikatami o błędach. (Chociaż czasami będziesz mieć jeden komponent, który generuje kilka różnych wyjątków, prawie nigdy nie powinieneś mieć tego samego wyjątku z wielu komponentów).

Moim zdaniem trudniej jest zaprojektować systemy oparte na wyjątkach, a początkowy czas programowania jest dłuższy, ponieważ musisz zbudować proces wyjątku na wszystkich poziomach N. Jednak na ogół systemy te są znacznie bardziej stabilne. Chociaż nigdy nie jest możliwe zaprojektowanie systemu, który „nie zawiedzie”, zaletą projektowania opartego na wyjątkach jest to, że zawsze oczekujesz awarii. Dla większości ludzi proces może być sprzeczny z intuicją. To tak, jakby pytać o drogę i kazać komuś powiedzieć wszystkim ulicom, których nie należy włączać.

Justin Ohms
źródło