Jak żyć bez wyjątków i bez Either

0

Witam,
W związku z licznymi postami żeby nie rzucać wyjątków na prawo i lewo to pytanie jak sobie z tym radzić ? Dodam że sposób z Either znam ale załóżmy ze nie można go wykorzystać.

Mamy przykład

public User addUser(User user) throw Exception{
        if (user.getName < 3 ) {
            throw new Jakiś tam Exception(z opsiem)
        }
       return userRepo.add(user)
    }

Jeżeli nie chcemy rzucać wyjątku, to co powinniśmy zwracać w takim serwisie ? Klase np UserResponse która ma pola User, Error i na jej podstawie później mapować na HttpResponse?
Coś nie mogę znaleźć odpowiedniego repo żeby podglądnąć jak z tym sobie poradzić

1
  1. Wyjątek
  2. Either/Try
  3. Własny obiekt z miejscem na dobrą i błędną odpowiedź

Tutaj zakładam, że chodziło o minimalną długość imienia (nie wiem czemu, przecież są takie imiona), więc fajnie by było wiedzieć czemu zwrócono błąd ('za krótkie imie'). Da się to uzyskać każdym sposobem, więc jak Ci wygodniej/jakie są ustalenia na projekcie

0

Można użyć wyjątku, czemu nie?To że ludzie nadużywają ich i komplikują kod to inna sprawa. Jednak w tym wypadku taka walidacja powinna zajść w konstruktorze klasy User.
Można też użyć Optional.

0
elwis napisał(a):

Można użyć wyjątku, czemu nie?To że ludzie nadużywają ich i komplikują kod to inna sprawa. Jednak w tym wypadku taka walidacja powinna zajść w konstruktorze klasy User.
Można też użyć Optional.

Takie akcje to lepiej w jakiejś statycznej fabryce + prywatny czysty konstruktor. Co do optionala to sie nie dowiesz dlaczego wystąpił błąd

0

@baant: jaki masz argument za fabryką? Nie widzę problemu żeby rzucić wyjątek w konstruktorze. Dla bardziej złożonego przypadku można użyć Buildera.
Co do braku komunikatu o błędzie, w rzeczy samej trzeba by było sprawdzać wynik, trochę bez sensu.

0

Po prostu wole jak konstruktor nie robi nic więcej poza konstruowaniem obiektu

0

Tutaj zakładam, że chodziło o minimalną długość imienia (nie wiem czemu, przecież są takie imiona),

To tylko przykład. Nie zwracałem uwagę co tam ma być. Chodziło mi tylko że przy najprostszej walidacji rzucam wyjątek. I tak mam np klasę, która sprawdzą walidacje usera i chciałbym wiedzieć co dokładnie ma nie tak. Złe imie: leci wyjątek że złe imie, krótkie hasło: leci wyjątek że krótkie hasło. (Ten sam wyjątek tylko z inną wiadomością)

Either/Try

Vavr własnie chciałem ominąć. Chciałem wiedzieć jak sobie dobrze z tym poradzić bez tej biblioteki. Nie zawsze można jej użyć a i dawniej jej nie było, więc trzeba było bez tego dobrze kodzić.

Własny obiekt z miejscem na dobrą i błędną odpowiedź

To własnie mi chodzi po głowie tylko nie byłem przekonany do tego pomysłu. Nie wiedzialem czy to słuszne podejście.

Jednak w tym wypadku taka walidacja powinna zajść w konstruktorze klasy User.

W sumie masz rację.

Głównie mi chodzi o podejście jak uniknąć rzucania wyjątków przy walidacji bądź innych prostych rzeczach które naturalnie mogą wystąpić. Np Uniknąć UserNameNotFoundException gdy usera nie ma w bazie. Póki co to przychodzi mi do głowy to co wyżej pisałem: Własny obiekt z miejscem na dobrą i błędną odpowiedź. Taki ubogi Either.

1

Rzuć własny wyjątek, mapowanie na response zrób za pomocą @ControllerAdvice jeśli korzystasz ze Springa. Jeśli nie korzystasz, to własny mapper na poziomie warstwy web.

2

Vavr własnie chciałem ominąć. Chciałem wiedzieć jak sobie dobrze z tym poradzić bez tej biblioteki. Nie zawsze można jej użyć a i dawniej jej nie było, więc trzeba było bez tego dobrze kodzić.

Javy8 tez kiedys nie bylo. Najlepiej utknac w czasach javy1 nie? Bo dawnie nie bylo ;)

4

W tym przypadku rozwiązanie to byłoby dokładnie UserResponse (można jak klasę bazową/interfejs z dwoma implementacjami OKResponse i ErrorResponse).
Tylko jak będzie miał więcej takich metod (jak addUser) to sie trochę napiszesz... Więc pewnie zrobisz to generycznie (OKResponse<T> { private T response; }... I w końcu wyjdzie, że zrobiłeś właśnie swojego EIthera, tylko gorszego.

Co do wyjątków - są dla ludzi, ale generalnie warto jednak używać tylko na sytuacje ostateczne - u Ciebie akurat własnie wyjątek, to żaden wyjątek (żadna panika) i raczej warto Eitherem pojechać. Dlaczego: Wyjatki się gorzej komponują, rzuconego wyjątku nie podstawisz pod zmienną (w intuicyjny sposób -wyjątek złapany w zmiennną przestaje być dalej propagowany ).
Gdyby to był Spring kontroller - i wyniku/wyjątku już bym w swoim kodzie nie łapał (bo byłby tylko przez spring obsługiwany i pchany na HTTP) to wyjatek nie byłby taki zły.

Co do VAVR nawet jeśli by tam Eithera (i Optiona) nie było to polecam ze względu na niemutowalne kolekcje. Jeżeli robisz typowy soft biznesowy to kolekcje z VAVR nie tylko są przyjemniejsze w użyciu (niż ta zabawa w stream(), collect()), są przede wszystkim bezpieczniejsze (mniej błędogęnne). Do tego w realistycznych przypadkach często wydajniesjsze(!!!), bo nie musisz stosować defensywnego kopiowania. To ostatnie dyskusyjne - mało kto stosuje defensywne kopiowanie (ale mi się czesto kiedyś zdarzało. wiec po przejsciu na VAVR moje procki odetchnęly). jakkolwiek w typowym biznesowym sofcie i tak wydajnoć kolekcji praktycznie nie ma znaczenia (jak często obrabiasz kolekcje większe niż 500 elementów?).

Jak zobaczysz jak Ci spada ilośc głupich błędów w logice to nie będziesz na java.util. chciał patrzeć (szczególnie w projektach zespołowych).

1

A tak swoją drogą jestem na 80% pewien że wprowadzą Either do JDK w przyszłości. Wprowadzily lambdy, streamy, teraz wprowadzaja pattern matching, only a matter of (long) time

1
scibi92 napisał(a):

A tak swoją drogą jestem na 80% pewien że wprowadzą Either do JDK w przyszłości. Wprowadzily lambdy, streamy, teraz wprowadzaja pattern matching, only a matter of (long) time

IMO nie dodadzą, i wcale nie wiem czy to źle.

W scali dodali Either i Try do standardowej biblioteki i dodali średnie Either jeszcze znośny, ale Try zrypany. W efekcie są te wbudowane oraz powstały Cats i ScalaZz własnymi implementacjami. Czyli nawet nie wiem czy nie większy bałagan...
Jak długo misją Goetza jest nie robić z javy języka funkcyjnego to lepiej żeby nie dodawali, bo wrzucą tylko jakąś kupę.

Co gorsza mam wrażenie, że więcej tam ludzi w wierchuszce nie wie jak takie fp działa itp. ale to potwierdze dopiero jak (jeśli*) przesłucham część dyskusji z JCrete Była fajna dyskusja na temat valhalla, a mnie nie było... Pośrednio usłyszałem straszne herezje (i widziałem na twitterze), ale może się przesłyszałem, nie znam kontekstu.

1

@jarekr000000: zaleta stosowania tego w standardowym API jest to że ludzie tego typu którzy mówią "hehehe nie możemy dodać VAVRA bo to Java a nie Scala" łatwiej się przekonuja.

1

Im więcej obiektów, tym więcej GC, tym większy czas CPU.

@tdudzik pozwoliłem sobie w poście napisac. Niby tak, ale tak naprawde to dzięki niemutowalności nie musisz robić kopi defensywnych, mysle że refenecji na LocalDate jest mniej potrzebnych niż na Calendar/java.util.Date. poza tym trzeba wziąć pod uwage że lepsze dla GC sa nowe obiekty wskaujące na stare niż odwrotnie ;)

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