Najlepsza alternatywa do wyjątków

2

@pieczarek moim zdaniem trochę słabo się tego będzie używaż poza trywialnymi przypadkami. Częściej jednak chcesz takie coś móc "komponować", np. robisz operacje X która może sfailować a potem wynik tej operacji, jeśli nie jest errorem, przekazujesz do kolejnej operacji która też moze sfailować. W efekcie te twoje klasy Response efektywnie musiałyby mieć takie API jak... Either właśnie :)

0

@Shalom: Wiesz co - nie spotkałem się z tym wzorcem w żadnych projektach .net. Wygląda ciekawie - musiał bym poćwiczyć z tym. Zazwyczaj obsługa błędów to szczegół implementacyjny i wspomniane podeście wystarcza. Niemniej to jest kocept. Nie widzę problemu, żeby te obiekty to były drzewa OperationResponse i żeby w środku była referencja na korzeń, czy listę liści. Niemniej faktycznie to trzeba jakoś wygodnie opakować, ale koncepcje Either chyba też trzeba samemu napisać w C#, chyba, że się mylę? Prawda niestety... że tak czy siak, źle bo trzeba to stworzyć, no i teraz pytanie czy my chcemy pisać logikę w dobrej jakości narzędziach i frameworkach, czy może chcemy tworzyć i utrzymywać framework? Mieszanie tego nigdy nie wychodzi na dobre.

1
pieczarek napisał(a):

@Shalom: Wiesz co - nie spotkałem się z tym wzorcem w żadnych projektach .net.

No to prawda, w dotnecie jest generalnie dzicz i łupanie kamieni, ale od paru lat wprowadzam to rozwiązanie do różnych firm i generalnie ludziom się podoba.

Zazwyczaj obsługa błędów to szczegół implementacyjny i wspomniane podeście wystarcza.

Właśnie przez to, że wielu traktuje to jako nieważny szczegół, zamiast zaprojektować od początku do końca spójnie we wszystkich warstwach aplikacji, to soft często wygląda, jak wygląda, a potem jest płacz i debugowanie, bo nie wiadomo co się dzieje.

Niemniej to jest kocept. Nie widzę problemu, żeby te obiekty to były drzewa OperationResponse i żeby w środku była referencja na korzeń, czy listę liści. Niemniej faktycznie to trzeba jakoś wygodnie opakować, ale

Też przez przesady, wystarczy jeśli taki OperationResponse<TData> zawiera albo prawidłowe dane, albo hierarchię błędów dziedziczących po jakimś ErroBase. Przykłady takich błędów to: ValidationError, ExceptionError, BusinessError - i dopiero z tego mogą dziedziczyć bardziej specyficzne błędy - ale tylko jeśli gdzieś są inaczej traktowane, bo jeśli mają tylko wrócić jako komunikat do użytkownika, to nie ma co rozbudowywać hierarchii.

koncepcje Either chyba też trzeba samemu napisać w C#, chyba, że się mylę? Prawda niestety... że tak czy siak, źle bo trzeba to stworzyć, no i teraz pytanie czy my chcemy pisać logikę w dobrej jakości narzędziach i frameworkach, czy może chcemy tworzyć i utrzymywać framework? Mieszanie tego nigdy nie wychodzi na dobre.

Istnieje trochę przerośniętych paczek do tego, zazwyczaj próbujących robić z C# język funkcyjny, co wygląda trochę jak przerabianie jamnika na ośmiornicę przy pomocy przybitych desek. Jeśli nie chcesz mieszać kodu biznesowego z infrastrukturą, to zawsze przecież można wyrzucić tych kilka klas do oddzielnej paczki.

0

Nie chodzi o podział kodu Po prostu jestem zwolennikiem używania tego co daje MS w ramach .net, c# i ASP plus ew. popularne nugety. Unikam do minimum pisania infrastruktury i mikroframeworkow. Nie chodzi o podział kodu, ale takie frameworki są zawsze niedorobione, zabuggowane i zamiast walczyć z logiką i problemem walczymy z biblioteką naszego autorstwa do rzeczy x. Tak mówi moje doświadczenie. Niemniej jak są paczki z implementacja, które używa już xx projektów to warto spróbować.

2
pieczarek napisał(a):

Po prostu jestem zwolennikiem używania tego co daje MS w ramach .net, c# i ASP plus ew. popularne nugety. Unikam do minimum pisania infrastruktury i mikroframeworkow. Nie chodzi o podział kodu, ale takie frameworki są zawsze niedorobione, zabuggowane i zamiast walczyć z logiką i problemem walczymy z biblioteką naszego autorstwa do rzeczy x. Tak mówi moje doświadczenie. Niemniej jak są paczki z implementacja, które używa już xx projektów to warto spróbować.

Czyli jak rozumiem:
1) napisanie (bool success, string error) (bo tak wygląda wielokrotnie quasi-either w C#) jest OK, bo tuple są wbudowane w język, mimo, że później lecimy z drabinką if-ów (które w sumie też są wbudowane w język
2) napisanie własnego Either/Result (mówimy o jednej klasie i parę extensionów) jest złe, bo trzeba utrzymywać micro-framework i pewnie jest zabugowane
3) użycie dużych bibliotek typu language-ext jest OK, bo są popularne, mimo, że to masa kodu, która nie jest nam potrzebna

W ogólności to co napisałeś ma sens, ale nie w tym konkretnym przypadku, gdzie koszt jest minimalny, a zysk ogromny.

0

@Saalin:

no a gdybyś sobie przekopiował najważniejsze klasy z language-ext?

i pewnie jest zabugowane

niesamowite jest ze ludzie potrafią walnąć projekty po >100k LoC, ale gdy trzeba napisać coś nawet małego, ale jest już na to biblioteka, to trzeba jej użyć bo pisząc samemu pewnie będą "jakieś bugi"

4

Dość się natrzepałem z bugami, wyciekami i problemami z wydajnością przy rzeczach, które już ktoś wymyślił i setki tysięcy ludzi używa. Mój kod, mając nawet sztab 50 testerów nie będzie tak przetestowany jak framework działający w milionach instancji. Po co pisać to samemu? Co z tego, że dociągamy wielką paczkę? Wielką - kilkaset KB czy nawet kilkadziesiąt MB - no i co z tego? Czy mój projekt ma 100MB czy 900MB DLL'i - szczerze nie obchodzi mnie to. To czy przy zwiększonym ruchu biblioteka okaże się bardziej dopracowana niż mój kod, bo nawet nie założyłem takiego ruchu - owszem bo to generuje realne straty.

Wole dociągnąć dużego nugeta niż wyciagać część klas - jak to potem aktualizować? Po to jest nuget, żeby łatwo podmieniać liba na nowego.

Dla mnie im mniej kodu powstaje tym lepiej, napatrzyłem się na to jak świat płonie przez pseudo frameworki. Żeby tworzyć bezpiecznie technologię trzeba mieć budżet większy niż projekty biznesowe, a biblioteka powinna działać w setkach projektów - wtedy można stwierdzić, że technologia jest przetestowana i się nadaje.

1
1a2b3c4d5e napisał(a):

no a gdybyś sobie przekopiował najważniejsze klasy z language-ext?

pieczarek napisał(a):

Wole dociągnąć dużego nugeta niż wyciagać część klas - jak to potem aktualizować? Po to jest nuget, żeby łatwo podmieniać liba na nowego.

Ale wcale nie chodzi o wielkość binarek czy cokolwiek takiego. Im większa biblioteka tym więcej błędów. Twierdzenie, że jeśli biblioteka jest popularna ma mało błędów jest fałszywe, a być może na odwrót - im większa biblioteka tym więcej okazji do błędów. Dziwne, że trzeba o tym przekonywać po ostatnich cyrkach z log4j.

Dociąganie zależności za każdym razem, gdy wydaje nam się, że to rozwiązuje nasz problem to potencjalnie dodawanie problemu. Szczególnie jeśli chcemy rozwiązać względnie prostą rzecz (np. jakąś prostą maszynę stanów), a bierzemy do tego wielki framework do workflowów, bo jest third-party i nie musimy go utrzymywać.

5

Dziwne, że trzeba o tym przekonywać po ostatnich cyrkach z log4j.

@Saalin

W ogóle bym nie mieszał do tego sytuacji z log4j, paradoksalnie. Spróbuj napisać własnego loggera ;)

W świecie, w którym ciągle wymyślamy koło na nowo (1) daleko nie zajedziemy, bo to nie jest żaden postęp pisać swojego loggera (2) wladujemy się w kłopoty i będziemy latać po nocach jakieś podatności. Log4j miał fatalna podatność, ale zadaj dobie pytanie, ile podatności wcześniej załatał, przed iloma fakapami Cię uchronił :) survivor bias to się chyba nazywa.

Ja rozumiem, że fajnie się pisze kod, ale lepiej ten czas spożytkować na pisanie sensownego kodu, który daje wartość, a przynajmniej wnosi coś nowego. Nikt nie potrzebuje 1535 implementacji loggera (na przykład).

1

Niepotrzebnie pojechałem z tematem log4j, sorry. Skupmy się na tym konkretnym - Either i jego implementacja w C#. Ja wcale nie jestem za pisaniem własnego kodu, kompilatorów, bibliotek - niepotrzebna ironia @pieczarek . Wręcz przeciwnie - lubię pisać jak najmniej kodu składając go z dostępnych klocków, bo w ten sposób zarabiam nie męcząc się. Gdyby naprawdę tym co rozważamy była alternatywa: weźmy bibliotekę, która spełnia nasze oczekiwania (tj. dostarcza Option i Either) lub piszmy to samemu to bym się rękami i nogami podpisał pod dodaniem zależności. Problem polega na tym, że najczęściej wtedy pada argument, że po co, skoro to dodatkowa zależność, która jest niekonieczna i już nawet w tym wątku padł ten argument (trochę niewprost):

pieczarek napisał(a):

Po prostu jestem zwolennikiem używania tego co daje MS w ramach .net, c# i ASP plus ew. popularne nugety.

I w ten sposób zamiast używać dobrych rozwiązań (bo takim jest zdecydowanie koncept Option i Either) kończymy z jakimiś ulepami (i wracając do tych nieszczęsnych tupli, którymi rzygam przy każdej okazji: przecież Tuple (success, error) jest izomorficzny z Either, jeśli to owrapujemy i dodamy do niego 2 extensiony, ale tego nie wolno nam robić, bo to już biblioteka wewnątrz projektu...)

Więc podsumowując:
Gotowe biblioteki > pisanie kodu samemu > rakowe rozwiązania wbudowane w język

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0