Работал с Ниной еще в Яндекс Деньгах - профессионал своего дела и очень приятная коллега! Я знаю, что уже тогда она изучала вопрос применения такого подхода применительно к android-разработке. Дико приятно видеть, что часть этого опыта она решила выложить в формате такого доклада - уверен, для большого числа людей если и не даст новых знаний, то освежит имеющиеся. Очень круто!
стоит за пределы андроида выйти, если не пробовали, мне rust и c помогли, вас может заинтересовать что-то ещё - много нового узнаете и кругозор в целом будет более широкий
сам юзаю Result уже не один год, удобно и нравится он мне. Но вот всё больше сталкиваюсь с тем, что гугловые библиотеки (типа пейджинга или биллинга) возвращают Flow. А оборачивать Flow с Result - выглядит уже монструозно. Перешел сейчас полностью на Flow, в принципе там тоже есть результат и эксепшин, но всё же немного это не то. Есть ли идеи как подружить это всё дело?
Посмотрите в сторону cqrs. Идея, что метод, который возвращает флоу только даёт доступ к данным но никак их не модифицирует. Если данные нужно изменить, то это делается другими методами. А вот те методов уже могут вернуть Result но без самих данных. За данными по прежнему нужно идти к flow.
Спасибо большое вам за комментарий, заставил меня очень призадуматься)) Работа с потоком данных, не кажется мне не естественной, для подхода, в котором мы говорим, что операция над данными - чистая функция. Ведь в целом Flow - это наш источник данных и он дает нам возможность применить операции (которые уже и будут чистыми) над этими данными. Тут есть два стула) если мы пишем код так что наши преобразования над потоком данных или генерация его, может вызывать исключения, вот тогда нам нужно оборачивать collect в try catch и там уже решать, что делать при ошибке с источником данных дальше. Или мы можем не вызывать исключений). По моему личному мнению в первом подходе как-то несимпатично все выглядит. Мне как разработчику хочется иметь стабильный источник данных, который в зависимости от ситуации либо возвращал мне только результаты и не валился почем зря, либо при возникновении ошибки кидал мне в поток данные которые для меня означают ошибку. Таким образом совмещая то, что я говорила в видео, в логике я хочу Flow к примеру резалтов(оставляем возможность возвращать флоу состояний как на ui, это если мы хотим устроить себе прям стейт машину для логики забыть про эксепшены и оперировать везде только состояниями), а на ui я хочу Flow состояний (State). И я все еще держу требование быть чистыми мои маленькие функции преобразований данных и работаю с потоками данных
@@ninasemkina8811 collect не обязательно оборачивать в try..catch. У Flow когда в emit будет ошибка, то она ловится где-то во вьюмодели в блоке catch (главное не забыть его вызвать). Да, у Flow есть все эти операторы - map, flatMap и еще много чего. Возможно про Result стоит уже и забыть. В общем я пока на переходной стадии - от Result не хочется отказываться, но видимо прийдется
Хороший доклад, сам уже юзаю Котлин Result двольно долго на своих проектах. Очень не хватает в нем стандартной flatMap😢 Из небольшого минуса отмечу только комбинацию его работы с WorkManager, ибо там работа должна возвращать свой Result, и это немного режет глаз. Но это больше претензия к самому WorkManager-y)
Result конечно хорош, но у него есть 1 большой, на мой взгляд минус - ошибки возвращаются только типа Throwable. а очень хочется, особенно для сетевых запросов, возвращать уже свой собственный тип ошибок. а видео полезное и интересное!)
@@AndroidBroadcast можно и свой собственный selead class написать. но придется либо дописывать красивые map, fold и тд, либо без них обходится. я очень надеюсь, что это доработается. раньше ведь Result вообще из методов нельзя было возвращать, а теперь на них архитектурную логику строят. хотя мне все чаще попадаются старички, воевавшие на RxJava, которые на Result смотрят сомнительно и любящие отлавливать ошибки во ViewModel. надеюсь, это видео даст толчок в массы и в сторону Result и его кастомных вариантов
Спасибо за видео. Интересно ваше мнение о том, как организовать cancellation у корутин в таком кейсе? Ведь CancellationException мы не должны перехватывать.
@@AndroidBroadcast а не будет ли это нарушать тот функциональный концепт за существование которого боролись на протяжении всего видео? Ведь exception, по словам Нины, это сайдэффект.
Вы правы в том что грубо говоря из-за CancellationException у нас не чистая ситуация, и я делаю вид что как бы все хорошо))) Тут приходится идти на копромис добиваясь честно говоря чистых функций в контексте логики проекта а не логики работы приложеня в целом. Ох уж эти компромисные компромисы только в теории все красиво практика все портит))
@@AndroidBroadcast Внутри у runCatching try-catch, который ловит CancellationException и не даёт родительской корутине его обработать. Это нарушает cancellation flow.
Нина, как андроид разработчик что вы можете сказать, по поводу постоянных "вредных обновлений ПО"? Под этим я подразумеваю ситуацию когда программа или оболочка андроида обновляется, и начинает тормозить на мощном железе. Хотя ничего нового с обновлением привнесено не было. Такая ситуация достоверно зафиксирована на ios и андроид. К примеру игра fruit ninja без каких либо изменений графики безбожно тормозит на ipad 3, но если путем определённых манипуляций поставить старую версию, и о чудо всё прекрасно работает! И так во всём ПО начиная от ютуба и дубльгиса, и заканчивая программами онлайн магазинов.
Не могу поспорить с тем что можно наблюдать ухудшения работы после обновлений, так как порой технологии которые в теории должны все ускорить наоборот тормозят, далеко ходить не надо просто вспоминая ситуацию с dagger и ksp. Но я не склонна верить в заговор о том что производители ПО намеренно ухудшают работу на старых телефонах, чтобы люди напокупали новых. Приложения имеют баги, могут быть неоптимизированны под новые версии ОС, обновления ОС могут иметь баги на конкретном железе, это возможно, делать из этого выводы о вредном намерение я считаю несколько опрометчивым
kotlin-result более подходящая, имхо, чем то что предполагает стандартная библиотека Но вообще после того как я толкала в разные проекты проекты, сейчас не знаю, как к этому относиться. Тут проблема гвоздя и молотка, и если знаешь про монады и чистые функции, хочется везде их толкать, а kotlin всё же на исключения больше настроен. Стандартная библиотека не использует стандартный же Result, о чём тут говорить Наверное, если язык изначально не был спроектирован с парадигмой errors as values, её навешивать не очень удачная идея
Ни в коем случае не берусь утверждать что это единственный верный способ написания, но из моей практики данные принципы давали прирост к стабильности и помогали сделать код более легким для чтения и понимания, и это было справедливо только в конкретном контексте для конкретных проектов.
еще некоторые синьористые синьоры уверены, что функциональное программирование - это длиннющие цепочки трансформаций. в результате получается нечто неподдерживаемое: три-четыре экрана из map flatmap foreach и прочего, в которых всё, от загрузки данных из апи и их трансформаций до... и нет, я не шучу про три-четыре экрана, я прямо сейчас в такое смотрю и подумываю об увольнении.
я как то в первый год своей работы столкнулась с вложеным тернарным оператором, там было 8 вложеных в друг друга тернарных операторов, очень вас понимаю, сил вам)
@@user-cp5er1hg9l Правильно fun g(s: String): Int = { s.length }. Есть книжка "Paul Chiusano Functional Programming in Scala", там очень подробно объяснено что такое чистые функции и сайд эффекты.
Над произношением надо поработать, не в обиду. Пока нету текста, понять о чем речь очень сложно. И очень много времени потрачено на ручной рефакторинг, есть же сочетания клавиш студии для рефакторинга
@@user-um4sg6tu9iвот так вумен момент. Разве я что- то не по делу сказал? Для хоткеев есть презентационный режим, показывает нажатия тостами. Не пришлось бы размазывать рефакторинг на 50 минут
Очень плохо - мое мнение. Теория объяснена плохо, галопом по европом и в видео абсолютно никак не применяется. Определения неправильные даны, видно непонимание самих концепций которые же и объясняются Каррирование называется currying правильно Код вначале видоса не компилирующийся вообще - перепутаны возвращаемые типы, параметры, использования, переменные. Еще и пример на f, g, h, что путает новичков (по моему скромному мнению) Советы даны плохие, Result мало кто уже использует, или kotlin-result, или ApiResult, или Arrow. Конечно готового метода flatmap нет - надо нормальные фреймворки использовать, где он есть :) Throwable нельзя ловить Either непонятно зачем был введен с учетом того, что про Result каждый второй джун знает, и назвать это "функциональным программированием" сложно, а речи про него вначале вообще не было Плохой английский очень, слушать тяжело с перепутанными понятиями и произношением Раздражает медленная скорость печати вручную, без горячих клавиш, смотрел на 2.0 Судя по использованию интерактора и его неправильному определению, сначала нужно выучить клин арч 29:32 Мы не создаем новую функцию - потому что функция инлайн... Ни от одного сайд-эффекта не избавились, все функции как были, так и остались "грязными", только не кидаются и не написаны наигранно плохо были... 41:47 - Как вводим функциональное программирование - удаляем весь неудобный код, потому что он "плохой". 44:41 - надо начать с правильного разделения на функции код и названий переменных, а "добавить в меня все друзья с имя" как-то не очень выглядит. 45:23 - давайте возвращать результат от инта, потому что мы даже не проверим ошибки которые произошли и просто выкинем в этом и всем предыдущем коде всю обработку ошибок. accumulate, partial существуют? Эксепшны никак не относятся к функциональщине...
Очень плохо - это такие soft скиллы у человека, который разрабатывает приложение для психического здоровья. Оценивать чужое произношение вы не можете, потому что у вас оно мягко говоря неидеальное.
🔗 Boosty abdev.by/s0Z
🔗 Android Broadcast Плюс abdev.by/q2A
🔗 Каналы "Android Broadcast" taplink.cc/android_broadcast
✉ Написать Кирилл kirill@androidbroadcast.dev
Для тех кому лень смотреть, видео про то, что надо возвращать Either из методов внутри которых может выбрасываться исключение.
Братан, ты из лиги лени?
То что ты спец многие новички знают, и это видео для новичков будет полезно.
@@umnikya7874нет не будет.
Также она подсветила плюсы использования референсов на методы, это тоже из функционального программирования
Работал с Ниной еще в Яндекс Деньгах - профессионал своего дела и очень приятная коллега!
Я знаю, что уже тогда она изучала вопрос применения такого подхода применительно к android-разработке. Дико приятно видеть, что часть этого опыта она решила выложить в формате такого доклада - уверен, для большого числа людей если и не даст новых знаний, то освежит имеющиеся. Очень круто!
Нина, спасибо огромное за выпуск!
Спасибо большое за выпуск, в очередной раз понял что тупой и учиться меня еще лет 10)))
Учиться есть всем специалистам, независимо от опыта. Не стоит так самокритично, особенно в начале. Хвалите себя чтобы не терять мотивацию
стоит за пределы андроида выйти, если не пробовали, мне rust и c помогли, вас может заинтересовать что-то ещё - много нового узнаете и кругозор в целом будет более широкий
Эксперт, легенда и просто хороший человек. Наконец-то я понял как улучшить архитектуру своего кода
сам юзаю Result уже не один год, удобно и нравится он мне. Но вот всё больше сталкиваюсь с тем, что гугловые библиотеки (типа пейджинга или биллинга) возвращают Flow. А оборачивать Flow с Result - выглядит уже монструозно. Перешел сейчас полностью на Flow, в принципе там тоже есть результат и эксепшин, но всё же немного это не то. Есть ли идеи как подружить это всё дело?
Посмотрите в сторону cqrs. Идея, что метод, который возвращает флоу только даёт доступ к данным но никак их не модифицирует. Если данные нужно изменить, то это делается другими методами. А вот те методов уже могут вернуть Result но без самих данных. За данными по прежнему нужно идти к flow.
Спасибо большое вам за комментарий, заставил меня очень призадуматься)) Работа с потоком данных, не кажется мне не естественной, для подхода, в котором мы говорим, что операция над данными - чистая функция. Ведь в целом Flow - это наш источник данных и он дает нам возможность применить операции (которые уже и будут чистыми) над этими данными. Тут есть два стула) если мы пишем код так что наши преобразования над потоком данных или генерация его, может вызывать исключения, вот тогда нам нужно оборачивать collect в try catch и там уже решать, что делать при ошибке с источником данных дальше. Или мы можем не вызывать исключений). По моему личному мнению в первом подходе как-то несимпатично все выглядит. Мне как разработчику хочется иметь стабильный источник данных, который в зависимости от ситуации либо возвращал мне только результаты и не валился почем зря, либо при возникновении ошибки кидал мне в поток данные которые для меня означают ошибку. Таким образом совмещая то, что я говорила в видео, в логике я хочу Flow к примеру резалтов(оставляем возможность возвращать флоу состояний как на ui, это если мы хотим устроить себе прям стейт машину для логики забыть про эксепшены и оперировать везде только состояниями), а на ui я хочу Flow состояний (State). И я все еще держу требование быть чистыми мои маленькие функции преобразований данных и работаю с потоками данных
@@ninasemkina8811 collect не обязательно оборачивать в try..catch. У Flow когда в emit будет ошибка, то она ловится где-то во вьюмодели в блоке catch (главное не забыть его вызвать). Да, у Flow есть все эти операторы - map, flatMap и еще много чего. Возможно про Result стоит уже и забыть. В общем я пока на переходной стадии - от Result не хочется отказываться, но видимо прийдется
Хороший доклад, сам уже юзаю Котлин Result двольно долго на своих проектах. Очень не хватает в нем стандартной flatMap😢
Из небольшого минуса отмечу только комбинацию его работы с WorkManager, ибо там работа должна возвращать свой Result, и это немного режет глаз. Но это больше претензия к самому WorkManager-y)
Пушка, бомба, где такие умницы обитают?
У нас в команде 🤩🙃
господа эксперты вам не кажется, что Throwable плохая задача возвращать, тк в наслениках у Throwable как Exception так и Error
Спасибо.
Result конечно хорош, но у него есть 1 большой, на мой взгляд минус - ошибки возвращаются только типа Throwable. а очень хочется, особенно для сетевых запросов, возвращать уже свой собственный тип ошибок.
а видео полезное и интересное!)
Так можно улучшить введением Generic
@@AndroidBroadcast можно и свой собственный selead class написать. но придется либо дописывать красивые map, fold и тд, либо без них обходится. я очень надеюсь, что это доработается. раньше ведь Result вообще из методов нельзя было возвращать, а теперь на них архитектурную логику строят.
хотя мне все чаще попадаются старички, воевавшие на RxJava, которые на Result смотрят сомнительно и любящие отлавливать ошибки во ViewModel.
надеюсь, это видео даст толчок в массы и в сторону Result и его кастомных вариантов
Блин она так красива,
Парни всегда так искренне пишут про девушек, а вот девушки так парням в IT тематиках не пишут 😁
чётко, без воды
Жду продолжение
Спасибо за видео. Интересно ваше мнение о том, как организовать cancellation у корутин в таком кейсе? Ведь CancellationException мы не должны перехватывать.
Ну так оно просто игнорируется в преобразовании в Result и выбрасывается дальше
@@AndroidBroadcast а не будет ли это нарушать тот функциональный концепт за существование которого боролись на протяжении всего видео? Ведь exception, по словам Нины, это сайдэффект.
Вы правы в том что грубо говоря из-за CancellationException у нас не чистая ситуация, и я делаю вид что как бы все хорошо))) Тут приходится идти на копромис добиваясь честно говоря чистых функций в контексте логики проекта а не логики работы приложеня в целом. Ох уж эти компромисные компромисы только в теории все красиво практика все портит))
@@ninasemkina8811обычное дело) демократия, чистая архитектура, функциональный подход - все хорошо лишь на бумаге)
@@AndroidBroadcast Внутри у runCatching try-catch, который ловит CancellationException и не даёт родительской корутине его обработать. Это нарушает cancellation flow.
Нина, как андроид разработчик что вы можете сказать, по поводу постоянных "вредных обновлений ПО"? Под этим я подразумеваю ситуацию когда программа или оболочка андроида обновляется, и начинает тормозить на мощном железе. Хотя ничего нового с обновлением привнесено не было. Такая ситуация достоверно зафиксирована на ios и андроид. К примеру игра fruit ninja без каких либо изменений графики безбожно тормозит на ipad 3, но если путем определённых манипуляций поставить старую версию, и о чудо всё прекрасно работает! И так во всём ПО начиная от ютуба и дубльгиса, и заканчивая программами онлайн магазинов.
Не могу поспорить с тем что можно наблюдать ухудшения работы после обновлений, так как порой технологии которые в теории должны все ускорить наоборот тормозят, далеко ходить не надо просто вспоминая ситуацию с dagger и ksp. Но я не склонна верить в заговор о том что производители ПО намеренно ухудшают работу на старых телефонах, чтобы люди напокупали новых. Приложения имеют баги, могут быть неоптимизированны под новые версии ОС, обновления ОС могут иметь баги на конкретном железе, это возможно, делать из этого выводы о вредном намерение я считаю несколько опрометчивым
За "pusser" лайк)
kotlin-result более подходящая, имхо, чем то что предполагает стандартная библиотека
Но вообще после того как я толкала в разные проекты проекты, сейчас не знаю, как к этому относиться. Тут проблема гвоздя и молотка, и если знаешь про монады и чистые функции, хочется везде их толкать, а kotlin всё же на исключения больше настроен. Стандартная библиотека не использует стандартный же Result, о чём тут говорить
Наверное, если язык изначально не был спроектирован с парадигмой errors as values, её навешивать не очень удачная идея
Ни в коем случае не берусь утверждать что это единственный верный способ написания, но из моей практики данные принципы давали прирост к стабильности и помогали сделать код более легким для чтения и понимания, и это было справедливо только в конкретном контексте для конкретных проектов.
Result по факту костыль, появившийся для смягчения жжения в садалищной зоне при обработке ошибок корутин.
еще некоторые синьористые синьоры уверены, что функциональное программирование - это длиннющие цепочки трансформаций. в результате получается нечто неподдерживаемое: три-четыре экрана из map flatmap foreach и прочего, в которых всё, от загрузки данных из апи и их трансформаций до... и нет, я не шучу про три-четыре экрана, я прямо сейчас в такое смотрю и подумываю об увольнении.
я как то в первый год своей работы столкнулась с вложеным тернарным оператором, там было 8 вложеных в друг друга тернарных операторов, очень вас понимаю, сил вам)
Дезертировать нельзя рефакторить. Каждый сам ставит запятую там, где считает нужным.
@@sylvanbird8788 )))) остро
кто-нибудь может объяснить код из начала видео fun g(s: String): Int = {x.length}, откуда х? где s? и почему тип Int?
Опечатка x на s поменяй и получишь функциональную ф-ию по получению длины строки
@@detribes228 ну то есть надо так? fun g(s: String): () -> Int = {s.length}
@@user-cp5er1hg9l Правильно fun g(s: String): Int = { s.length }. Есть книжка "Paul Chiusano Functional Programming in Scala", там очень подробно объяснено что такое чистые функции и сайд эффекты.
Скорее всего всё же
fun g(s: String): Int = s.length
Иначе val h = f(g(s)) не скомпилится
прошу прощения опечатка fun g(s: String): Int = {x.length} => fun g(s: String): Int = {s.length} ну а тип инт потому что length у CharSequence это Int
А почему гитхаб такой пустой 🤔 Не основной что-ли
Да это не основной))) это грустная для меня история как гитхаб заблочил мне аккаунт личный из за санкций для компании)))
Вот бы ещё ссылку на видео с result в retrofit
czcams.com/video/FGYbjBsCZ7c/video.html
Подскажи таймкод где оно там, пожалуйста
Походу везде. Или ошибка или пилите через dynamic proxy
@@AndroidBroadcast 21:58
Сложна
Весь доклад предвкушал чистые функции, а по итогу чистый только маппер. Все остальные сущности имеют сайд эффекты
Все было хорошо, пока я не услышал "саксефул". Ну блин. Такой серьезный разговор и это
Над произношением надо поработать, не в обиду.
Пока нету текста, понять о чем речь очень сложно.
И очень много времени потрачено на ручной рефакторинг, есть же сочетания клавиш студии для рефакторинга
Хотела оставить возможность людям ускорять видео на столько на сколько им хочется) и хоткеи могут внести неясность на видео того что происходит
А вам над слухом и тактичностью.
@@user-um4sg6tu9iвот так вумен момент.
Разве я что- то не по делу сказал?
Для хоткеев есть презентационный режим, показывает нажатия тостами. Не пришлось бы размазывать рефакторинг на 50 минут
@@yura3882633 «вуман момент» - как маркер обнуления любой ценности всего пойнта 😂
Очень плохо - мое мнение.
Теория объяснена плохо, галопом по европом и в видео абсолютно никак не применяется.
Определения неправильные даны, видно непонимание самих концепций которые же и объясняются
Каррирование называется currying правильно
Код вначале видоса не компилирующийся вообще - перепутаны возвращаемые типы, параметры, использования, переменные. Еще и пример на f, g, h, что путает новичков (по моему скромному мнению)
Советы даны плохие, Result мало кто уже использует, или kotlin-result, или ApiResult, или Arrow. Конечно готового метода flatmap нет - надо нормальные фреймворки использовать, где он есть :)
Throwable нельзя ловить
Either непонятно зачем был введен с учетом того, что про Result каждый второй джун знает, и назвать это "функциональным программированием" сложно, а речи про него вначале вообще не было
Плохой английский очень, слушать тяжело с перепутанными понятиями и произношением
Раздражает медленная скорость печати вручную, без горячих клавиш, смотрел на 2.0
Судя по использованию интерактора и его неправильному определению, сначала нужно выучить клин арч
29:32 Мы не создаем новую функцию - потому что функция инлайн...
Ни от одного сайд-эффекта не избавились, все функции как были, так и остались "грязными", только не кидаются и не написаны наигранно плохо были...
41:47 - Как вводим функциональное программирование - удаляем весь неудобный код, потому что он "плохой".
44:41 - надо начать с правильного разделения на функции код и названий переменных, а "добавить в меня все друзья с имя" как-то не очень выглядит.
45:23 - давайте возвращать результат от инта, потому что мы даже не проверим ошибки которые произошли и просто выкинем в этом и всем предыдущем коде всю обработку ошибок. accumulate, partial существуют?
Эксепшны никак не относятся к функциональщине...
Очень плохо - это такие soft скиллы у человека, который разрабатывает приложение для психического здоровья.
Оценивать чужое произношение вы не можете, потому что у вас оно мягко говоря неидеальное.