Czy powinno się unikać metod, które nic nie zwracają (void)?

0

Czy powinno się unikać method, które nic nie zwracają? Jakie są alternatywy? Np. mamy metodę, która po walidacji dodaje usera do bazy danych. Co mogłaby zwrócić taka metoda? Tego usera? Boola w zależności od powodzenia operacji?

3

Generalnie to nie widzę nic zdrożnego w tym, żeby metoda zwracała void.

Z alternatyw to możesz zwrócić ciąg opisujący poszczególne operacje i potem wykonać przy pomocy jakiegoś nadrzędnego bytu. Takie podejście ma chyba nazwę na m...

Jeśli w wyniku takiej operacji coś powstaje to dobrze jest to zwrócić. W przypadku zapisu usera do bazy to jak najbardziej można zwrócić.

Zwracanie boola jak dla mnie jest słabe, bo łatwo to zignorować. Jak się coś wywali to albo rzuć wyjątkiem albo zwracaj Either/Result/jakkolwiek to się nazywa w Twoim języku.

0
Edelner napisał(a):

Czy powinno się unikać method, które nic nie zwracają? Jakie są alternatywy? Np. mamy metodę, która po walidacji dodaje usera do bazy danych. Co mogłaby zwrócić taka metoda? Tego usera? Boola w zależności od powodzenia operacji?

Mam wrażenie że niechęć do void'a wywodzi się z paradygmatu obiektów niezmienniczych (immutable). W tym patrzeniu void to metoda zmieniająca stan, więc wróg.

bool jest kiepski, to jest bardzo w stylu "C".
Jak się nie uda nie daje żadnej informacji. Rzuca się wyjątkami, dla zwolenników programowania funkcyjnego Either

12

Czy powinno się unikać method, które nic nie zwracają?

Tak, bo ciężko testuje się side-effecty, są też generalnie mniej czytelne i jeśli masz coś void to wiadomo że to musi robić pod spodem jakieś mutacje stanu, więc automatycznie nie będzie też thread-safe.

Jakie są alternatywy?

Zwracać wynik xD

Np. mamy metodę, która po walidacji dodaje usera do bazy danych. Co mogłaby zwrócić taka metoda? Tego usera? Boola w zależności od powodzenia operacji?

Moim zdaniem niech zwraca Either<Error,User> dzięki czemu można sobie jeszcze wygodnie składać kilka walidatorów za pomocą flatMap i na koniec wychodzisz z errorem albo z jakimś użytecznym obiektem.

1

Rzadko kiedy jest tak, że kod który nie jest pure (no bo od tego zazwyczaj jest programowanie - robienie side effectów)

jest również "safe", czyli nie robi nic takiego, co mogłoby pójść nie tak, a zatem prawdopodobnie da się w najgorszym wypadku boola zwrócić lub coś lepszego typu jakiś Result

ale nie ma co na siłę uciekać przed voidem

1

Ciężko uniknąć takich metod w przypadku GUI. Alternatywa? Metody w stylu boolean isError(); i Error getLastError();. Nie są one idealne, ale w tym przypadku to ma sens. Wiem, to wymyka się poza OOP, ale programowanie to nie utopijny świat programów bez błędów.

5

Metody void są mocno błędogenne, szczególnie przy refaktoringu (łatwo zapomnieć, wykomentować, łatwo przestawić je w "złej" kolejności).

Alternatywa nieczysta:

  • zwracaj identyfikator użytkownika (ewentualnie razem z błędem Validation<Error, UserId>),
    (jak piszę w javie, w dysfunkcjonalnym zespole to szukam takich rozwiązań (zwykle się da))

Alternatywa czysta:

  • zwracaj monadę (IO),
    ale tu raczej trzeba chcieć, lubieć pisać funkcyjnie - w całym zespole no i java średnio się do tego nadaje

Nie chce tutaj tego rozwijać - robię to przydługo w tym video:

(gdzieś w połowie są naleśniki - czyli monady)

5
Edelner napisał(a):

Czy powinno się unikać method, które nic nie zwracają? Jakie są alternatywy? Np. mamy metodę, która po walidacji dodaje usera do bazy danych. Co mogłaby zwrócić taka metoda? Tego usera? Boola w zależności od powodzenia operacji?

"metodę, która po walidacji dodaje usera do bazy" - to znaczy, że prawidłowy user wchodzi do tej metody, czy ta jedna metoda i waliduje, i dodaje do bazy?
Bo jeśli to drugie, to to nie jest jedna metoda tylko dwie metody, na dodatek w dwóch klasach.

Jeśli chodzi o sam wynik takiej metody dodającej do bazy, to zwróciłbym obiekt usera lub obiekt błędu z konkretnymi informacjami na temat tego, co zaszło.

0

@somekind: To jest agregat. Ma wstrzyknięty validator userów i repository. Metoda tego agregatu przyjmuje usera, potem następuje walidacja przez ten validator i w zależności od wyniku user jest zapisywany lub nie w bazie.

1

Czemu agregat ma walidator, jakiego rodzaju jest to walidacja?
Po co mu repozytorium? Repozytorium powinno zapisywać agregat wywołane z poziomu jakiegoś serwisu aplikacyjnego albo domenowego.

0
somekind napisał(a):

Czemu agregat ma walidator, jakiego rodzaju jest to walidacja?

Po co mu repozytorium? Repozytorium powinno zapisywać agregat wywołane z poziomu jakiegoś serwisu aplikacyjnego albo domenowego.

Chyba się nie zrozumieliśmy. Nie chodziło mi o agregat w sensie ddd tylko o klasę, która łączy ze sobą różne komponenty w celu przeprowadzenia operacji.

4
Edelner napisał(a):

Czy powinno się unikać method, które nic nie zwracają?

IMO tak, ciężko testować, czy coś, co nic nie zwraca (lub wręcz zachowuje się dokładnie tak samo niezależnie od rezultatu) w ogóle działa. Trudno stwierdzić, czy cokolwiek robi, szczególnie jak ma side-effect który sam w sobie jest trudny do zweryfikowania.

A jak już się uda to przetestować, to prawdopodobnie w bardzo uciążliwy sposób. Niezależnie od powodzenia (względnego) w testowaniu - z tego czy innego powodu to będzie źródło frustracji w przyszłości :(

3

szczególnie jak ma side-effect który sam w sobie jest trudny do zweryfikowania.

Niby tak, ale nie do końca
Ale faktycznie, lepiej nie zwracać void ;)

3
Aleksander32 napisał(a):

szczególnie jak ma side-effect który sam w sobie jest trudny do zweryfikowania.

Niby tak, ale nie do końca
Ale faktycznie, lepiej nie zwracać void ;)

TestContainers nie gwarantuje testowalności, nie postawisz na nim wszystkiego (choć możesz próbować).

Dostałem kiedyś do zrobienia zmianę w projekcie-kasztanie, w którym testów praktycznie nie było, same @SneakyThrows i voidy, a ów kasztan namiętnie uderzał do serwera Git oraz serwera CI w celu skonfigurowania obu (!!!).

Teoretycznie oba byłem w stanie postawić na TC, ALE w praktyce było tyle zależności między wszystkimi elementami tej układanki, że nie dało się z tego zrobić stabilnych testów.

Oczywiście są jeszcze rozwiązania pośrednie tzn. wiremock, ale wtedy musisz się pałować z setupem wiremocka dla kilku kobył (serwer Git, serwer CI), a w dodatku tracisz możliwości przetestowania problematycznych kawałków - które, jak się okazało, bywały naprawiane na placu boju przez sleep 10 itp. :)

0

Jak drajwujesz kod wymaganiami / testami, to zwykle potrzeba zwracania wyniku / statusu ładnie wychodzi od razu. Zwykle klient jest zainteresowany tym, czy operacja się udała. Wyjątkiem, który przychodzi mi do głowy, są asynchroniczne metody - dlatego, że z definicji nie ma nikogo, kto by czekał na wynik :)

0

void faktycznie może w pewien sposób utrudniać testowanie, ale do takich sytuacji są mocki. Poza tym, jeśli masz publiczną metodę void i nie masz pojęcia, co ona może zwrócić, to nie ma się co wysilać moim zdaniem. Nie widzę niczego złego w prywatnych voidach.

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