Как с треском провалить миграцию с Java на Kotlin в Android приложении

Как с треском провалить миграцию с Java на Kotlin в Android приложении

С тех пор, как Google объявила об официальной поддержке Kotlin в Android, всё больше разработчиков хотят использовать его в своих новых и существующих проектах. Поскольку я также большой поклонник Kotlin, я не мог дождаться, когда смогу использовать Kotlin в своём рабочем проекте. В конце концов, Kotlin полностью совместим с Java, и все разработчики просто в восторге от этого. Так что же может пойти не так?

Ну, на самом деле многое может пойти не так. Меня просто пугает то, что на странице официальной документации Android «Начало работы с Kotlin» написано, что если вы хотите перенести существующее приложение на Kotlin, вы должны просто начать писать модульные тесты, а затем, после небольшого опыта работы с этим языком, вы должны писать новый код на Kotlin, а существующий Java-код просто конвертировать.

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

Познакомьтесь с моим маленьким проектом 🐶🐱

У меня был проект, который я создал более года назад на Java, и мне нужно было немного его изменить и добавить один новый экран. Я подумал, что это отличная возможность проверить, действительно ли миграция существующего проекта на Kotlin очень проста, как все говорят. Исходя из рекомендаций официальной документации, я начал с написания на Kotlin модульных тестов. Новые классы я тоже писал на Kotlin и конвертировал некоторые существующие. Казалось, что всё замечательно, но через некоторое время я обнаружил одну неприятную проблему.

Kotlin + Lombok = 😓

В моем приложении я использовал библиотеку Lombok для генерации геттеров и сеттеров. Lombok — это обработчик аннотаций для javac. К сожалению, компилятор kotlin использует javac без обработки аннотаций [источник]. Это означает, что методы, созданные при помощи Lombok, будут недоступны в Kotlin:

Методы, созданные при помощи Lombok, будут недоступны в Kotlin

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

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

Kotlin + Lombok + Dagger 2 = 😰😖💀

В моём приложении используется Dagger 2 для внедрения зависимостей. При создании нового экрана я обычно создаю структуру MVP: Activity, Presenter, Component, Module и Contract. Все зависимости для презентора внедряются с помощью Dagger. Activity вызывает DaggerSomeComponent.builder().(...).build().inject(this), чтобы внедрить презентор с необходимыми для себя зависимостями.

Использование Dagger 2 вместе с Kotlin — не проблема. Только перед этим нужно применить kapt-плагин, который создает необходимые самогенерируемые классы для Dagger.

И вот здесь всё начинает разваливаться

Без kapt-плагина я не мог использовать сгенерированные Dagger-классы в файлах Kotlin. Но после того, как я добавил этот плагин, все методы, созданные Lombok, исчезли!

До применения kapt-плагина:

До применения kapt-плагина

После применения kapt-плагина:

После применения kapt-плагина

И, к сожалению, решения этой проблемы нет. Вы можете применять либо только kapt-плагин, либо только Lombok. К счастью, поскольку это был всего лишь мой маленький проект, я просто удалил Lombok и сам написал геттеры и сеттеры. Но в этом проекте было всего около 50 сгенерированных методов. В проекте, который мы поддерживаем на работе, у нас их около тысячи. Удаление Lombok из этого приложения просто невозможно.

Также, очевидно, что отказ от kapt-плагина — не выход из ситуации. Без него вы не сможете использовать Kotlin в классах, где используется Dagger. В моем случае я должен был бы реализовать Activity, Component и Module на Java, и только Contract и Presenter могли быть написаны на Kotlin. А смешивание файлов Java и Kotlin — это определенно не здорово. Вместо плавного перехода с Java на Kotlin вы просто создали бы большой беспорядок.

Вот так выглядела бы эта ужасная полиглотная MVP-структура без kapt-плагина:

Ужасная полиглотная MVP-структура без kapt-плагина

Но я всё же хочу перейти на Kotlin. Что мне делать?

Один из способов — использовать разные модули. Kotlin не увидит методы, которые Lombok будет генерировать в исходном коде, но будет видеть их в байт-коде.

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

И это ещё не всё. В смешивании файлов Kotlin и Java без чёткого разделения есть много других недостатков. Это заставляет всех разработчиков, работающих с вами над проектом, знать оба языка. Также это уменьшает читаемость кода и может привести к увеличению времени сборки [источник].

Кратко

  • методы, сгенерированные Lombok, не видны в Kotlin;
  • использование kapt-плагина ломает Lombok;
  • без kapt-плагина вы не cможете использовать самогенерируемые классы для Dagger в Kotlin, что означает, что вам всё равно придётся писать новый код на Java;
  • способ решить эту проблему — вывести Kotlin в отдельные модули;
  • смешивание файлов Kotlin и Java в больших проектах без чёткого разделения может привести к неожиданным проблемам совместимости.

Перевод статьи «How to fuck up Java to Kotlin migration in your existing Android app»

ПОХОЖИЕ ПУБЛИКАЦИИ

793
02/08/2018

2 комментариев к статье "Как с треском провалить миграцию с Java на Kotlin в Android приложении"

  1. Почему статьи пишут такие дол…бы???

Добавить комментарий