Kiedy używać programowania reaktywnego a kiedy synchronicznego w perspektywie komunikacji REST'owej

0

Witam,
Chciałbym się dowiedzieć jakimi czynnikami powinienem się kierować przy wyborze architektury opartej o komunikację restową?
Konkretnie mam tutaj na myśli wyświetlanie statystyk danych, zaciąganych z bazy NoSQL (MongoDB) przez Javę. Backend w Javie służyłby do obliczania m.in statystyk i wystawianiu ich na warstwę widoku, gdzie miałbym Angulara.

1

A jesteś wstanie oszacować docelowy ruch?

Prawdopodobnie nie potrzebujesz w ogóle reaktywności.

0

Rozumiem, a jaki byłby use-case kiedy musiałbym rozważyć reaktywność? Bardzo dużo zapytań do Api?

2

Mówi się, że tyle co Netfix.

Pamiętaj, że reaktywność to też narzut na "koszt" tworzenia kodu (jest "brzydszy")

4
danek napisał(a):

Mówi się, że tyle co Netfix.

Pamiętaj, że reaktywność to też narzut na "koszt" tworzenia kodu (jest "brzydszy")

A ja bym powiedział, że wręcz przeciwnie. Piszesz wszystko czysto funkcyjnie i kod jest DUŻO prostszy i "ładniejszy":

userService.getFavorites(userId, new Callback<List<String>>() { 
  public void onSuccess(List<String> list) { 
    if (list.isEmpty()) { 
      suggestionService.getSuggestions(new Callback<List<Favorite>>() {
        public void onSuccess(List<Favorite> list) { 
          UiUtils.submitOnUiThread(() -> { 
            list.stream()
                .limit(5)
                .forEach(uiList::show); 
            });
        }

        public void onError(Throwable error) { 
          UiUtils.errorPopup(error);
        }
      });
    } else {
      list.stream() 
          .limit(5)
          .forEach(favId -> favoriteService.getDetails(favId, 
            new Callback<Favorite>() {
              public void onSuccess(Favorite details) {
                UiUtils.submitOnUiThread(() -> uiList.show(details));
              }

              public void onError(Throwable error) {
                UiUtils.errorPopup(error);
              }
            }
          ));
    }
  }

  public void onError(Throwable error) {
    UiUtils.errorPopup(error);
  }
});

To samo funkcyjnie:

userService.getFavorites(userId) 
           .flatMap(favoriteService::getDetails) 
           .switchIfEmpty(suggestionService.getSuggestions()) 
           .take(5) 
           .publishOn(UiUtils.uiThreadScheduler()) 
           .subscribe(uiList::show, UiUtils::errorPopup);

2
danek napisał(a):

Mówi się, że tyle co Netfix.

Pamiętaj, że reaktywność to też narzut na "koszt" tworzenia kodu (jest "brzydszy")

Pomijając że to 100% subiektywne stwierdzenie, to jest na tyle brzydszy na ile osoba go pisząca pozwoli. Co to w ogóle za pomysł że kod reaktywny jest brzydszy? To samo można powiedzieć o jakimkolwiek innym rodzaju kodu/paradygmacie.

Z resztą z tym Netflixem też ciekawe stwierdzenie. Mówi się gdzie? Tam gdzie widziałeś brzydki kod? :D

@mieszko30 może te artykuły trochę pomogą:
https://docs.microsoft.com/en-us/dotnet/architecture/microservices/architect-microservice-container-applications/asynchronous-message-based-communication
https://docs.microsoft.com/en-us/azure/architecture/patterns/publisher-subscriber

2

TL;DR jeśli nie zyskasz na „wydajności”, nie rób tego

2

Co do prezentacji powyżej - jest jeszcze kwestia jezyka.
Przykład z prezentacji wygląda dużo lepiej po przerobieniu na scalę : https://gist.github.com/jarekratajski/2adb5680b28388339636578ccf6ab6f8

Ja to widzę tak: początkujący, szczególnie w javie, nie powinni ruszać tego reactive prawie w ogóle.
Jak ktoś potrzebuje wydajności to powinien poznać (ale nie musi używac).
Jak ktoś pisze funkcyjnie i rozwija się w tym kierunku to też na reactive sam trafi. Szczególnie w Scali, czy Haskellu działa to naturalnie. W kotlinie... jak mamy pewne reguły kodowania.
Z ciekawostek - w JS reactive też jest naturalnym rozwiązaniem.

Co do debugu itp., jest gorzej niż debugowanie kalkulatora 1+1, ale takiego wielkiego dramatu nie ma. Na pewno mniej męczące niż debugowanie czegokolwiek na serwerach JavaEE, czy szukanie co się stało z kontekstem security w springu :-) (Hooks.onOperatorDebug() faktycznie pomaga )

Najgorszy problem - błędy w projectreactor. To dziwne, że projekt, który jest tak popularny i ma już ładnych parę lat i wersji... ma tak absurdalne błedy czasem (see isssues na githubie zwłaszcza pozamykane w ostatnim roku). Jak się na takiego buga trafi to można się zdenerwować.

Drugi problem - pole minowe. Znowu dotyczy Javy, mniej troche kotlina, jeszcze mniej Scali - trzeba uważać. Nie cierpię tworów, które wprowadzają sztuczną dodatkową dyscyplinę. W reactive
prosta dyscyplina jest taka, że subscribe to robimy JEDEN raz na dany "process". W ostatnim kroku, albo najlepiej wcale, jeśli inna biblioteka ciągnie dane z naszego strumienia. Niestety w jezyku (programowanui) imperatywnym można to zrobić więcej niż raz, i to przypadkiem, i często będzie to działać. W końcu gdzieś kiedyś po małym refaktoringu się wywali i bedzie bolało. Jeszcze śmieszniejsze jest nie zrobienie żadnego subscribe i pozostawienie zainicjowanego strumienia.
To chyba najczęstszy problem z reactive jaki się pojawia w pytaniach, problemach na forach - czasem wcale nie jest łatwo znaleźć gdzie jest ta zwałka (nadmiarowy subsribe, całkowity brak subscribe).

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