
BG Development · За реклама · За контакти |
![]() ![]() ![]() ![]() ![]() |
Здравей! ( Включване | Регистриране ) |
Страници: (2) [1] 2 ( Първото ново мнение ) | ![]() ![]() ![]() |
thrawn |
Публикувано на: 20-02-2025, 08:58
|
||||||
![]() Име: Група: Потребител Ранг: Почетен член Мнения: 3730 Регистриран на: 17.01.17 ![]() |
Играя си с една имплементация на web сървиз която искам да направя реактивна. Самото API ми връща Response обект (който съдържа http статусът). При успех на заявката извиквам onNext с получения response обект а при изключение onError (със самото изключение). Проблемът в постановката е, че при subscribe получавам response обектът на едно място, Независимо от http статусът. Логичното решение в, да използвам обикновен if/else за да определя статусът и да си извикам съответната логика:
Това работи перфектно, просто е и четливо. Ама на някой места, гледам че се обясняват как не било реактивно. На други твърдят, че няма проблеми ... Та втори опит. Правя два абоната И във всеки филтрирам отговорите на база HTTP статус:
Това работи горе долу добре (с hot observable) но има недостатък, че при изключение Main::onError се извиква два пъти. Трети опит. Правя два потока (изглежда ми ненужно) в които филтрирам по HTTP статус, Задавам междинни манипулатори на onNext и след това обединявам потоците.
Това работи добре, но ми изглежда малко пресилено. Въпросът ми е, как се решава подобен проблем в реактивното програмиране? И има ли изобщо смисъл да се вкарвам в подобно приключение след като мога просто да използвам if/else (вариант 1)? |
||||||
thrawn |
Публикувано на: 20-02-2025, 09:58
|
||||
![]() Име: Група: Потребител Ранг: Почетен член Мнения: 3730 Регистриран на: 17.01.17 ![]() |
Следващ опит, който изглежда малко по-чисто разчита на мой оператор
Но пък самата имплементация на оператора използва if/else
|
||||
thrawn |
Публикувано на: 20-02-2025, 10:30
|
||||
![]() Име: Група: Потребител Ранг: Почетен член Мнения: 3730 Регистриран на: 17.01.17 ![]() |
Същия подход го приложих, като се абонирах с мой observer.
И самата фабрика
Всичко е ОК, само дето това е пряко повторение на първия вариант, но с повече код... Ако някой има идеи как е редно да се подходи да казва ![]() |
||||
relax4o |
Публикувано на: 20-02-2025, 21:45
|
||||||
![]() Име: Група: Потребител Ранг: Почетен член Мнения: 2829 Регистриран на: 04.04.07 ![]() |
А кога хвърля изключение? Предполагам при неуспех да се свърже и подобни мрежови проблеми? Честно казано, първия вариант, който си дал, според мен, е напълно валиден практически. Това е масов проблем(или пък не) с http client-и. Може да се замаже с един map() и фасада в сървиза, който извиква http client-а (или каквото е там).
Решението във втория пост е също добро според мен и го предпочитам пред третия ти пост. Така или иначе от if/else не можеш да избягаш, освен ако не можеш да имплементираш интерсептор на всички заявки и при response на >=400 да хвърляш къстъм изключение, което не вярвам да предпочиташ като решение. Въпреки че и там ще имаш проверка поради естеството на това как работи клиента. Не съм ползвал Java, но като гледам работи на подобен принцип като в Angular и rxjs. -------------------- Бисери :D
|
||||||
thrawn |
Публикувано на: 21-02-2025, 08:45
|
||||
![]() Име: Група: Потребител Ранг: Почетен член Мнения: 3730 Регистриран на: 17.01.17 ![]() |
Ами RxJava е имплементация за java на реактивното api на reactivX. RxJS съответно е имплементацията за javascript. Та двете би следвало да са почти еднакви (с дребни езикови различия де). Така че, каквото е валидно за javascript в rxjs би трябвало да е валидно и тук (та java практически не ти трябва. Спокойно можеш да даваш решение/я на javascript). Генерирането на самия Observable обект не е интересно (спецификата, че става дума за web api). Емитнатите данни могат да са дори прости числа и да трябва да предприемем различно действие в зависимост от самото число. Основния момент тук е, че се въвежда терминът "реактивно програмиране" и съответно се почват някакви разпалени обяснения как if/else, for ... не бива да се ползват в контекстът на реактивното програмиране. Съответно почват да се появяват подобни тривиални проблеми (Може би, от липса на опит, знам ли. Затова и пуснах темата). Та като се замисля, когато в java въведоха stream апи-то (синтактично няма разлика с реактивното апи) коментирахме точно итерирането на потоци. Та тогава, ако не се лъжа Stilgar каза, че като свикна да го ползвам ще ми е търсене да пиша цикли, и беше прав. Сега почти винаги го ползвам. Затова, ако направим аналогия между двете, то избягването на подобни структури се прилага само при модифициране и/или трансформиране на потока или данните в него. Докато обработката на самите данни (било в крайните точки, или в междинните) може да се извърши както е по-удачно. А причината за различните мнения е, че хората които са прекалено ентусиазирани от самото апи генерализират докато хората с опит (може би) казват, че няма лошо да се ползва императивен стил на програмиране във функциите. Това е първия вариант по двата начина
--- Що се касае до самото api, то изключенията са в следствие на проблеми я по връзката, я с парсването на данните. Абе грешки. Докато http статус кодовете, въпреки че, носят информация за грешка то не винаги се третират като такава. Да речем 401 ще предизвика влизане в процедура по автентикация (логин). 404 при заявка за търсене не се третира като грешка а отговор няма данни (вместо празен обект). 500 в повечето случаи носи информация за настъпено ограничение в базата данни (нещо вече съществува, друго не може да бъде изтрито защото се използва). И въпреки, че е възможно всичко това да се вкара в изключения то употребата на try/catch за управление на бизнес логика в приложение е много неудачно. Всичко дискутирано до тук приема за успешни заявки с код 200 - 299 Това мнение е било редактирано от thrawn на 21-02-2025, 09:00 |
||||
relax4o |
Публикувано на: 21-02-2025, 11:55
|
||||||
![]() Име: Група: Потребител Ранг: Почетен член Мнения: 2829 Регистриран на: 04.04.07 ![]() |
Да ти кажа, работа с http клиенти се различава до някъде от реактивно програмиране на каквото и да е друго, защото като програмисти всичко от 400 нагоре го третираме като грешка и очакваме да го обработваме като такава в onError, но тука случая е друг, защото имаш и изключения за реални грешки, а всички статуси се третират като валиден response. За това понякога трябва да си прагматичен с решенията, колкото и да не ти харесват. Практически в Ангулар аз лично правя нужното трансформиране в сървиза, където се използва http клиента, след отговор от АПИ-то. Избягвам да трябва да върша много проверки там, където се събскрайбвам (по компонентите), защото прави кода нечетим. Също избягвам subscribe() в subscribe() или в който и да е метод по чейна, защото при промяна по observable не ти гарантира канселиране на вътрешните събове. По-добре е да ползваш switchMap/flatMap/concatMap в такива случаи. Аз лично твоя случай сигурно ще го реша с прост map в сървиза, както посочих в предния си пост.
Редовна практика е при нас (може би и на нас ни куца опит) да ремапнем отговора, но го правим в сървиза, за да можем в компонентите чисто да се абонираме и да използваме отговора. Вече, ако има конкретна логика, която да трябва да се изпълни в компонента, си я правим с subscription-а. Като гледам и Нетфликс използват същата практика като мен. https://speakerdeck.com/benjchristensen/fun...m-2013?slide=45 . Можеш да разгледаш всички слайдове отначало, ако го намериш за интересно. -------------------- Бисери :D
|
||||||
thrawn |
Публикувано на: 21-02-2025, 12:50
|
![]() Име: Група: Потребител Ранг: Почетен член Мнения: 3730 Регистриран на: 17.01.17 ![]() |
В примерът ти се разчита на това, че httpClient е реактивен (предполагам) и сам ще си прихване и емитне изключенията. Защото ако не е така, то ще има проблем при липса на връзка да речем.
Иначе, в ревюто което си дал (точно линкнатите слайдове с map) наистина си ползват императивна логика. За съжаление, при представянето на обсървърът са свели примерът до println. Но като цяло почва да ми се затвърждава мнението, че генерализирането на темата е погрешно. Имай в предвид, че това което давам като примери е гола работна постановка (набита в статичен контекст). В крайна сметка, api-то ще следва същия синтаксис като потребителя ще трябва да посочи поне един от трите манипулатора onResponseOk, onResponseError и onError (е, плюс посочване на remote интерфейс и подаване на съответните параметри). Реално от вън няма да се вижда конкретната имплементация. Това мнение е било редактирано от thrawn на 21-02-2025, 13:00 |
goro |
Публикувано на: 21-02-2025, 12:56
|
||
Име: Група: Потребител Ранг: Активен Мнения: 171 Регистриран на: 31.05.09 ![]() |
Аз, като любител, надничащ тук основно за да се ограмотявам, бих ползвал if/else, ако другия вариант не ми дава нещо повече. |
||
thrawn |
Публикувано на: 21-02-2025, 13:06
|
||||
![]() Име: Група: Потребител Ранг: Почетен член Мнения: 3730 Регистриран на: 17.01.17 ![]() |
Тук става дума за принципен проблем. Не получаваш нищо в повече или по-малко. Просто подходът е различен. В императивното програмиране сам си взимаш данните докато в реактивното чакаш някой да ти ги сдъвче и изплюе на готово ![]() |
||||
relax4o |
Публикувано на: 21-02-2025, 13:50
|
||||||
![]() Име: Група: Потребител Ранг: Почетен член Мнения: 2829 Регистриран на: 04.04.07 ![]() |
В примера ми се разчита на това - да, защото практиката ми е такава в Ангулар, но винаги можеш да обърнеш отговора от non-reactive http client в observable и да го третираш така отвън, ако смяташ, че си заслужава да създаваш фасадата. Общо взето, понякога трябва да сме прагматични и да изберем решението, което най-много ни утърва в случая. Няма много къде да се сгреши практически, освен когато хората викат subscribe() в друг subscribe() вместо да ползват switchMap(и подобните) и се чудят защо има необясними странични ефекти. -------------------- Бисери :D
|
||||||
![]() |
![]() ![]() ![]() |