Как стать автором
Обновить

Комментарии 37

Чтобы разобраться с этой библиотекой каждому новому разработчику потребуется от 12 до 20 часов. Вы теряете почти 3 дня! Как раз за эти 3 дня Вы можете запилить свою пагинацию и быть независимым от сторонних решений.

Так ведь со своей пагинацией тоже разбираться всем новым разработчикам придётся. Плюс если с либой разработчик может разобраться путем гугления, то в случае каких-то непоняток с внутренним решением придется отвлекать коллег. В общем, немного неоднозначно. Если функционал сложный и есть хорошая либа, то часто она может быть лучше.

Спасибо за комментарий!

Я не представляю как можно написать удобную библиотеку для пагинации для всех приложений. Я изучил решения от Google и даже в их примерах полно багов с PagingLibrary 3, а в PagingLibrary 2 я нашел много ограничений, к сожалению. Поэтому в статье я склонялся к тому, что пагинацию надежнее писать самому.

С основным посылом комментария я полностью согласен. В своей группе в ВК я опубликовал пост, в котором написал, что если фича очень тяжелая в реализации (например, отображение PDF документа), то лучше использовать готовую либу. Ещё раз спасибо за замечание, это стоило отметить в статье.
Например, библиотека Realm может увеличить размер APK с 4MB до 12MB

Ну значит не используйте realm, если вам не нужны все его фичи, используйте что-то другое. Использовать библиотеки != отключать голову.

Почти каждый разработчик, начиная работать с EventBus, использует его повсюду. В итоге проект становится абсолютно нечитаемым.

От того, что разработчик начнет таскать по приложению самописную шину вместо eventbus, его код чище не станет.

Чтобы разобраться с этой библиотекой каждому новому разработчику потребуется от 12 до 20 часов. Вы теряете почти 3 дня! Как раз за эти 3 дня Вы можете запилить свою пагинацию и быть независимым от сторонних решений.

Новый разработчик с ненулевой вероятностью уже работал с гугловой либой, и тогда его затраты на обучение будут нулевые, ваш же велосипед он гарантированно видит впервые в жизни. И не забудьте приплюсовать стоимость тестирования и багофиксов.

Не знаю почему библиотекой до сих пор активно пользуются после появления Kotlin

Потому что в kotlin'е нет механизма DI.

и OkHttp, и Retrofit

Ретрофит использует OkHttp в качестве http-клиента.
Спасибо за комментарий!

Поддерживаю каждое Ваше замечание.

По поводу DI в Kotlin я имел ввиду, что можно использовать Koin, Kodein, Toothpick или прокидывать зависимости руками. Каждый из этих вариантов добавляет меньше объема сгенерированного кода, проще отлаживается и внешне выглядит гораздо проще.
добавляет меньше объема сгенерированного кода

Тут спорно. Программист меньше пишет, это да. Большой минус, что нет совместимость с java, например, у kodein. Считаю, что крупные библиотеки надо использовать не боясь, а у маленьких смотреть, что под капотом
Полностью с Вами согласен

Нужно внедрять библиотеку относительно требований проекта. Также существуют проверенные библиотеки, которые показали себя на практике и их можно использовать не боясь.
К таким библиотекам могу отнести:
— Room
— Retrofit
— Библиотеки для работы с Firebase
Не знаю почему библиотекой до сих пор активно пользуются после появления Kotlin
Что? С каких пор язык стал заменять инструмент для внедрения зависимостей?
Спасибо за комментарий)

Язык может заменить многие инструменты. Например, те же паттерны проектирования в каждом языке видоизменяются. А в Kotlin паттерн Singleton пишется одним ключевым словом object. Аналогично работает и с другими инструментами.

Благодаря Kotlin делегатам, Kotlin DSL и некоторым другим фишечкам Kotlin появились такие библиотеки как Tootkpuck, Koin, Kodein. И как раз благодаря Kotlin мы можем прокидывать зависимости гораздо проще.
Помимо либ мы можем написать DI руками, используя делегаты, который внешне будет выглядеть гораздо проще, чем Dagger. К сожалению, я потерял статью, в которой было описано как красиво можно написать DI на Kotlin делегатах :(
Помимо либ мы можем написать DI руками, используя делегаты

Так это не DI, это service locator. Что Koin, что Kodein, по сути, не особо уменьшают связанность классов, они просто перемещают это в другое место. Toothpick, в принципе, то же самое.

Плюс у них отсутствует проверка наличия зависимостей во время компиляции. В маленьком приложении это не так проблемно, а вот в большом это будет вполне себе заметно — раз за разом где-нибудь при тестировании (а то и в продакшене) будет оказываться, что кто-то забыл предоставить зависимость.

Плюс Dagger редко требует от меня явного прописывания создания объектов — если объекту просто нужно предоставить зависимости, я помечу его scope-аннотацией, помечу конструктор @Inject — и готово, объект будет создан. Явное создание объектов в моделях нужно только в случае, если объект создается нетривиально, в остальных случаях я могу либо не использовать модули, либо использовать @Binds. В Koin/Kodein мне придется каждый раз писать, как именно создавать объект. Сейчас я работаю над очень большим проектом, в котором используется Dagger 2, и, скажу честно, я очень рад, что я могу просто объявить класс, объявить его зависимости, пометить конструктор аннотацией — и все, больше мне не нужно ничего делать.

Ну и лично мне очень нравится, как scopes устроены в Dagger 2. Они очень дисциплинируют и не позволяют бездумно раздавать объекты направо и налево.

А в Kotlin паттерн Singleton пишется одним ключевым словом object.

С objectом нужно быть очень осторожным, иначе получите плохотестируемое нечто. А если нужен синглтон с зависимостями, то object отправляется гулять. ИМХО, object я бы использовал только либо как хранилище графа объектов, либо как подкласс sealed класса, у которого нет состояния (ну или какие-то util штуковины).

Аналогично работает и с другими инструментами.

Можно еще примеров? Моя фантазия, к сожалению, ставит меня в тупик.

К сожалению, я потерял статью, в которой было описано как красиво можно написать DI на Kotlin делегатах

Не она, случайно?
proandroiddev.com/lets-build-our-own-simplified-version-of-koin-19a887306258
То, что Koin и Kodein не DI, а Service Locator — это не мешает им быть прекрасными инструментами для прокидывания зависимостей.
Да, я согласен, что у них есть свои минусы по сравнению с Dagger (как и свои плюсы). Но все же Dagger подходит для более узкого числа проектов, чем остальные либы. Если Dagger действительно подходит для проекта и упрощает жизнь, то заюзать можно. При этом важно, чтобы разработчик, использующий Dagger, использовал его правильно. Но когда Dagger используют таким образом:
— Нет Binds
— Для всего пишут Provides
— Все помечено аннотацией Singleton
— Скоупы нигде не хранятся
то проект превращается в кучу костылей, которые отовсюду летят в тебя.
На самом деле я и сам сторонник Dagger, в какое-то время я его достаточно глубоко изучал и использовал в проекте. А Koin, Kodein и Toothpick я изучал лишь в теории, но на практике не использовал.
В общем, хоть Dagger и классный, но в большинстве проектов он не подходит по большей части из-за своей сложности. Не многие джуны, мидлы и даже сеньоры находят силы его полноценно изучить, к сожалению.

С objectом нужно быть очень осторожным, иначе получите плохотестируемое нечто

Полностью согласен. Он заменяет, конечно, паттерн Singleton, но как и с паттерном с object надо быть аккуратным.

Можно еще примеров? Моя фантазия, к сожалению, ставит меня в тупик.

Паттерны — делегат, строитель. Работа с асинхронностью — корутины. Но мне кажется, что это уже не сильно связано с темой статьи)

Не она, случайно?

Не она. Тут видимо просто хотят скопировать Koin. Если Koin хорошо работает из коробки, то в таком коде мало смысла. Другим разработчикам будет лишь сложнее разобраться с кодом. ИМХО

В целом, моя статья предназначена для новичков, миддл разработчиков, которые любят внедрять в свой проект новые либы, не задумываясь о последствиях. Надеюсь, кому-то она действительно поможет)
В общем, хоть Dagger и классный, но в большинстве проектов он не подходит по большей части из-за своей сложности

Вот тут полностью согласен, инструмент действительно недружелюбный к новичкам. До сих пор помню, как я не мог понять, как же Dagger работает со scope-ами.
К сожалению, официальный туториал все еще использует ужасный пример с Thermosiphon'ом.

>Паттерны — делегат, строитель. Работа с асинхронностью — корутины.
Так. Есть вероятность, что я чего-то не знаю, поэтому спрошу — в Kotlin есть какая-то особая поддержка Builder'ов? Или вы имели в виду возможность сделать свой DSL?

Работа с асинхронностью — корутины

Оффтопик, но еще бы объяснялось в туториалах лучше, как именно они работают… Я слабо представлял, как корутина может прыгать между тредами (Это же один метод, думал я!) и «приостанавливать» тред и исполнять там другой код, пока не посмотрел под капот, и не понял, что вызов (очень условно) каждой
suspend fun
просто нарезает функцию на вызовы с коллбэками.
в Kotlin есть какая-то особая поддержка Builder'ов?

Да не, впринципе так же. Но некоторые разработчики считают, что в Kotlin лучше использовать строитель не через цепочку вызываемых методов, а через именованные параметры. Порой это выглядит читабельнее, но это спорный вопрос.

еще бы объяснялось в туториалах лучше, как именно они работают

Это точно. Сам как-то задавался таким вопросом. В итоге где-то на просторах YouTube нашел 2-х часовую лекцию, где в подробностях разбираются кишки корутин. Если не ошибаюсь канал называется ComputerScience. Но, к сожалению, понять как работают корутины внутри действительно непросто в связи с малым количеством годного материала на эту тему.
Был великолепный на мой взгляд пример, когда разработчик решил использовать свой велосипед для работы с датами вместо того, чтобы использовать уже готовую библиотеку. И все бы ничего, если бы 29-го февраля вся система (а это был биллинг интернет-провайдера) не встала раком. А все почему? Да потому, что свои грабли роднее.
Если серьезно, то бездумная разработка что с внешними библиотеками, что без них — приведет к проблемам рано или поздно.
Спасибо за комментарий!

Как показывает практика гораздо чаще приходишь в проект и видишь кучу лишних зависимостей, которые вдобавок ещё и некорректно используются. Например, многие используют Dagger даже не понимая как работают скоупы :)

Конечно же, везде есть золотая середина. Самое главное — думать головой что и когда использовать.
Я сторонние библиотеки использую с максимальной осторожностью. Если предполагается, что библиотека глубоко интегрируется в приложение, то лучше написать обёртку над ней с более удобным API. Тогда её вытряхивание из проекта не станет болью. Достаточно будет изменить только код обертки.
Спасибо за комментарий!

Я очень рад разработчикам, которые осознанно внедряют библиотеки в свой проект :)
Выпилили вы все библиотеки, приложение стало в 5 раз меньше чем у конкурентов и шустрее.
А пользователь смотрит и думает: вот 10 приложений похожих, у девяти размер 10 МБ, а у одного 2 МБ. Что-то тут нечисто!
Чаще всего процесс оптимизации начинается после привлечения основной массы пользователей, а не до нее. И кстати я на размер приложений очень редко обращал внимание, больше полагался на отзывы.
А вы сами как много отзывов написали?
С опытом приходит понимание баланса.

— Где-то нужна не «ключевая» логика приложения — типа работы с датами. Нет смысла писать свое
— Где-то архитектурная либа, ее внедрение — это архитектурное решение, большое и на годы, а не просто «давайте подключим Rx»
— Где-то либа подходит, но сырая или заброшенная
— Какую-то либу используют все и новые люди не будут ни в чем разбираться

Я бы сформировал так

— Код лучше не писать, чем писать
— Лучше писать код для продукта чем сервисный
— Лучше свое чем чужое, но заброшенное или неподходящее
— Усилия по внедрению либы и подгонку ее под нужные сценарии не должны превышать стоимость своего кода.
— Консистентность проекта важнее нововведений (если это не процесс миграции)
Полностью с Вами согласен. Жаль, что понимание баланса приходит с годами.

Спасибо за комментарий!
а не просто «давайте подключим Rx»

За такое я бы руки отрывал. Rx — мощнейший инструмент, при использовании которого все приложение строится по-другому, но для некоторых это всего лишь способ вынести запросы на сервер в другой тред… и в итоге наблюдаешь subscribe внутри subscribe
Вот вот! :)
Понятная идея, но по факту:
— Пришел на проект с зоопарком либ. Допустим, на них реализованы оригинальные виджеты. Удалить их нельзя, т.к. не дадут время на изучение вопроса и написание своего кода. Из продукта фичу вырезать нельзя;
— Или, приходит product-manager\owner, упрощенно говорит: хотим так же, как у вот этих двух приложений. Нашей экосистеме это подходит. Дизайнер выпускает дизайн под обе платформы. И получается, что надо за спринт сделать свой условный «календарь», «чат» и что угодно, причём на виджетах и с анимациями, которых на твоей платформе нет.
Вариант скорее всего будет быстро найти готовое решение, пойти на компромисс с дизайнером.
Согласен

Спасибо за комментарий!
Думаю тут зависит от того какой бюджет закладывается в проект, есть ли время сделать качественный продукт или все таки нужно сделать кое-как, но по-быстрому

Я убежден в том, что если бездумно тащить в проект библиотеки, когда нужно внедрить какую-то новую фичу, написать качественный проект не получится.
Пришел на проект с зоопарком либ. Допустим, на них реализованы оригинальные виджеты. Удалить их нельзя

Ну нельзя и нельзя. А есть такая задача, удалить все библиотеки?

Вариант скорее всего будет быстро найти готовое решение, пойти на компромисс с дизайнером.

Вот это очень важное замечание. Стороннее решение — всегда компромисс. Мы не гарантируем оптимальность решения, но уже на входе получаем более сбалансированное решение, чем самописное.
Безусловно, если бизнес скажет «надо тоже самое, но с перламутровыми пуговицами» — или форк, или велосипед, или дальше искать готовые реализации. И какой из способов будет больнее — это еще большой вопрос.
Хе-хе.
Допустим вы получили замечательную и платную библиотеку от RSA. А через какие-то 3-5-20 лет она загнулась. RSA уже не пишет такого. Что делать?

Почти всегда и везде сталкивался с тем, что удаляют или забрасывают библиотеки. Или в них не чинятся баги по «загружености автора», а в гитхабе висят PR+issue.
И естественно форкать такую библиотеку — то еще удовольствие.

Я бы сказал, что самые попсовые библиотеки или самые легкие — это то, что нужно брать. Все остальное будет стрелять и тут и там.

Я бы обходил стороной не гововые либы — там всегда может запал закончится, а тебе разгребать )))
Скажите пожалуйста, чем заменили AndroidPdfViewer?
youtu.be/dj8SN6OLl58?t=939
Мой рассказ о том, почему велосипеды хуже библиотек.
В целом посыл автора абсолютно понятен — не усложняйте проект когда не надо.
Вот только велосипед априори хуже библиотеки, потому что
— выражает позицию узкой группы разработчиков
— менее проработан чем популярные решения
— неизвестен другим разрабам
— не протестирован
— не поддерживается должным образом (я про обновления androidx, kotlin)
Прослушал Ваш доклад. Согласен с мыслью, изложенной в нем. Писать свои велосипеды для тех случаев, когда что-то уже хорошо реализовано и протестировано действительно не стоит. Например, я в своем проекте использую Room, Retrofit, ViewModel&LiveData и некоторые другие библиотеки, в которых я уверен. Но думаю, что важно убедиться, что данная библиотека действительно подходит вашему проекту (Порой библиотеки с кучей багов и без должной оптимизации могут вполне подходить Вашему проекту).
Согласен. А еще я специально упомянул контрибьюторство как вариант воплотить свое желание творить. Это гораздо продуктивнее, чем писать все с нуля.
Спасибо за статью. Не упомянута ещё одна причина.
Повышение версии SDK
Когда я переходил на Котлин, в рекомендациях упоминался Fuel вместо Retrofit. Да, я изучал его грабли, обходил, думал, будет проще. Оказалось, ошибок там было не меньше, анализировать запросы даже сложнее, но последней каплей стал переход на 19 API. После этого в течение месяца я переписал все запросы на Retrofit и ушёл с Fuel. Однако и здесь не всё было гладко, год назад OkHttp перешёл на 21 API, после чего я перестал обновлять Retrofit. Причём об изменениях может быть сказано на сайте, но minSdkVersion при этом может не поменяться в самой библиотеке, что почти гарантированно приведёт к падению приложения в проде из-за несовместимостей. И причина падения сначала будет сбивать с толку (именно так и было с Retrofit: «java.lang.NoClassDefFoundError: java.util.Objects»).
Забавно, но во всей странице не было упоминания слова SDK.
Если библиотека уже интегрирована в проект, при увеличении SDK стоит дилемма: либо фиксировать версию библиотеки в dependencies, либо увеличивать SDK приложения. Если это библиотека типа Firebase, то приходится поднимать SDK.
Если вы ещё только планируете внедрять библиотеку, приходится отфильтровывать многие новые, т.к. они запросто могут начинаться с 21 или 23 API.

Также можно добавить к устареванию не поддерживаемой более библиотеки такую проблему: к обновлению Андроида и появлению новых устройств старая библиотека уже не будет готова. Так было в YandexMapKit несколько лет, когда карты не обновлялись и падали на новых устройствах.

Ещё к проблемам я бы добавил исправление issues. В моей практике библиотеки Джека Вортона типа Picasso отличаются плохим отношением к программистам. Issues там закрывались часто просто так, без объяснений. Такие библиотеки лучше не брать, т.е. сначала изучаем issues.
Также надо аккуратно брать последние альфа- и бета-версии библиотек. Они могут поддерживать нужный в данный момент функционал, но внезапно меняться и содержать новые баги. Иногда лучше скачать aar-версию, чем указать на альфа-версию в gradle, т.к. некоторые авторы меняют библиотеки по любой прихоти (пример, опять же, Picasso). Сегодня она работает, а завтра будет падать, причём узнаете об этом в проде, когда apk уже выложен после сборки.
Спасибо за комментарий!

Я полностью разделяю Вашу точку зрения и придерживаюсь аналогичного подхода.
Я хотел добавить пункт «Повышение версии SDK», но я не мог найти весомого примера, который отображал бы потенциальную проблему. Я благодарен за аргументированный комментарий. Когда будет время, я постараюсь обновить статью, добавив туда мысли из Вашего комментария)
Спасибо! Тогда лучше «Повышение минимальной версии SDK».

Вспомнил ещё такой кейс. Если библиотека уже использует в составе другую библиотеку и вы тоже используете эту, вторую библиотеку, но другой версии, то могут быть проблемы. Как-то писали, что если есть ссылка на Glide другой версии, то могут быть странные падения (не проверял).

Не знаю, надо ли упоминать и такой кейс. Если есть множество библиотек в gradle, то они должны быть плюс-минус последних версий. Т.к. многие из них друг от друга зависят, то даже просто компиляция старого проекта может стать сложной задачей, а обеспечить совместимость библиотек разных версий вообще нереально.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации