Search
Write a publication
Pull to refresh
34
0
Федор Игнаткевич @Jeffset

Android разработчик

Send message

issue#23 на подумать про то, как не писать лишние билдеры.

Большое спасибо за статью и детальные данные измерений! Рад, что получилось провести тестовую миграцию и подсветить возможные проблемы. В общем случае на любые проблемы, предложения и даже вопросы (тег help wanted) можно смело заводить issue на github. Давай попробую пройтись по подсвеченным проблемам.

Насчет необходимости писать все билдеры/фабрики компонентов руками Yatagan.builder(MyComponent.Builder::class.java). Да, к сожалению, так нужно делать в Yatagan. Это обсусловлено поддержкой рефлексии. Если ванильный Dagger и мог помочь нам и сгенерировать билдер самостоятельно, то рефлексия ничего генерировать не может. Ей обязательно нужен какой-то готовый интерфейс билдера, который она сможет динамически реализовать - такой же подход применяется и в dagger-reflect. А разрешать автогенерацию билдеров для kapt/ksp и ничего не делать для рефлексии - сломает возможность бесшовного переключения бэкендов. Если есть идеи, как упростить жизнь в этом моменте и не ломать совместимость кодогена и рефлексии - буду очень рад предложениям. Был упомянут "менеджер зависимостей", было бы интересно узнать подробнее.

Да, Yatagan не разрешает скоупы на @Binds, так как по нашему опыту использования это больше приводит к ошибкам, чем дает профита. Вместо этого Yatagan разрешает иметь несколько скоупов на биндинге, чтобы избавить разработчика от надобности писать @Binds в разные скоупы.

Насчет того, что приходится делать некоторые сущности public из-за того, что Yatagan отказывается работать с package-private сущностями. Пока это так, это частично обусловлено поддержкой рефлексии и отсутсвием сгенерированных фабрик. Есть issue#22, где будем пробовать ослабить требования public/internal, где это окажется возможно.

Вообще я очень рад, что KSP бэкенд завелся без проблем и показал хорошие результаты. У самого KSP есть неприятные проблемы, в том числе с моделированием Java-кода, так что на сложных конструкциях могут быть "приколы", которые стоит репортить. Потому статус поддержки KSP в Yatagan пока экспериментальный.

Напоследок добавлю, что документацию планируем доработать, проблемы с ней известны. Можно начать следить за issue#20. Поддержку и развитие не планируем прекращать, так как сами живем на этом в продакшене. И очень рады новым интеграторам!

Еще раз спасибо за статью. Если остались какие-то вопросы, пиши!

Спасибо. По опыту миграции больших проектов это вполне реальная задача, и мы успешно мигрировали несколько продуктов у себя внутри. Главное, внимательно прочитать документацию по различиям Yatagan и Dagger, оценить объем правок, необходимых для того, чтобы код заработал на Yatagan. Постепенная миграция возможна в том смысле, что правки можно делать ещё в рамках Dagger - заменить все @Nullable привязки, явно декларировать subcomponent'ы; удостовериться, что все декларации компонентов являются интерфейсами и так далее по доке - это все можно делать постепенно, не ломая совместимости с Dagger. После этого, достаточно будет просто автоматически заменить package-name в импортах и починить оставшиеся проблемы, которых должно быть немного, в рамках финальной миграции. Специальных инструментов миграции пока нет.

Yatagan не лучше чем Kodein, они решают немного разные задачи. Например, если вы только начинаете свой проект, и у вас есть возможность выбрать DI-фреймворк и вы выберете Kodein - то скорее всего останетесь доволны. А если у вас большой проект, который уже давно использует Dagger - то Yatagan может улучшить вам жизнь.

Интересный поинт. Да, верно, для рефлексии нужен явный интерфейс, который можно реализовать и который может быть использован в клиентском коде. Не обязательно декларировать явный Component.Builder только тогда, когда компонент корневой и у него нет внешних зависимостей - тогда используется Yatagan.create. Так что, автоматически генерировать такие вещи не получится. Если вам это интересно, то можете предложить решение, которое будет учитывать рефлексийный бэкенд, в github issue и его, вероятно, можно будет реализовать, если оно будет достаточно общим.

Вероятно, скорость "холодной" сборки улучшилась значительно по сравнению с kapt, тут я, к сожалению, не проводил детальных измерений. Скорость инкрементальной сборки, улучшение которой стояло у меня как основная цель, улучшилась на ~5% в различных сценариях по сравнению с kapt, но, ввиду того, что KSP-бэкенд несколько раз разламывался при обновлении версии из-за багов KSP в поддержке Java, мы так и не смогли его хорошенько обкатать и измерить реальный профит. Так же KSP-бэкенд наверное может работать немного медленее, чем мог бы, из-за того, что нужно конвертировать Kotlin-сущности в Java для генерации Java кода. Ситуацию планируем исправить в версии 2.0.0, где задумывается поддержка KMP и генерации кода на Kotlin в KSP - если проект получит интерес. Сейчас я расчитываю получить фидбэк по использованию KSP в текущем виде от pure-Kotlin проектов, так как у нас такого опыта ещё нет.

Да, DI можно организовывать очень по-разному, в зависимости от потребностей и архитектуры приложения. Если я верно прочитал предложенный код, то принципиально такое же решение у нас и было, оно было описано в статье в разделе про историю и IoContainer: иерархия словарей стратегий (builder) как создавать зависимости. Вместо companion-object мы использовали Class<?>. Предложенное в комментарии решение предполагает, что мы вручную достаём из прокинутогоAmbient все зависимости, вместо того, чтобы рефлексийно получить информацию о параметрах @Inject конструктора и автоматически внедрять зависимости. Насколько я понял, проблему с опциональными зависимостями предлагается решать через "дефолтные" реализации зависимостей: нет явного оверрайда - может использоваться no-op реализация. Это хороший подход, но как было описано, для нашего проекта было бы очень тяжело формулировать такие no-op реализации, в то время как для других проектов это может быть хорошим вариантом. Так что в задачи DI у нас входила возможность предоставления зависимостей в форме Optional<T>. Так же, у нас в проекте до сих пор очень много Java кода.

Касательно производительности предложенного решения в рамках очень больших графов так же могут быть вопросы (много лямбд, companion-object), такое решение может в некоторых случаях работать не быстрее чем на рефлексии, как показывает практика.

Итого, делать можно по-разному, каждый выбирает, что ему больше подходит. Спасибо, очень интересный код на idiomatic Kotlin для сравнения!

Information

Rating
Does not participate
Date of birth
Registered
Activity