Программирование
Золотой век Kotlin и его неопределенное будущее
В компании Infobip с 2017 года и до сегодняшнего дня идет золотой век Kotlin. Будет ли он продолжаться, зависит исключительно от JetBrains и их способности внедрять инновации в Kotlin. Переломным моментом станет 2025 год.
Лучшие времена всегда позади
За 10 с лишним лет работы инженером-программистом в Infobip много времени, если не большую его часть, я потратил на сопровождению кода. Чаще всего это был чужой код.
Мне повезло, или не повезло, в зависимости от того, как вы к этому относитесь, видеть, как различные технологии растут и откатываются назад, чтобы больше никогда не использоваться в новых проектах.
Один из таких случаев произошел в 2014 году. Команда, создавшая и поддерживавшая один продукт в Infobip, распалась, и мне пришлось взять его на себя и поддерживать. В нем было все самое современное — node.js, Cassandra, MongoDB, Redis, MSSQL, Groovy, Grails, ELK и так далее. Не так уж важно, кто, как и почему выбрал все эти технологии. Важно лишь то, что сложность была безумной.
Сложность убила проект
Моей первоначальной команде потребовалось больше месяца, чтобы просто настроить все локально и запустить проект и опробовать его. Очень скоро меня перевели в другую команду, где мне поручили создать прототип, MVP-продукт, который делал бы то же самое, что и тот, который мы должны были поддерживать, но с минимальным набором технологий.
Мы создали его так же, как и большинство других продуктов в Infobip. Старая добрая Java, MSSQL и… и все. Это было в 2015 году, а этот сервис живет и по сей день, в 2023. Сложность первого проекта погубила его. Хуже того, она погубила и команду, которая должна была его поддерживать.
Мораль этой истории такова: вы должны быть очень осторожны с бюджетом на сложность. Речь идет не только о количестве сервисов или библиотек, которые вы поддерживаете, но и о количестве различных технологий, которые вам нужно поддерживать, а также о перспективах развития той или иной технологии.
Когда Groovy был groovy
В 2013 году одним из самых популярных языков на JVM была не Java, а Groovy. В нем были лямбды, динамические структуры, конструкторы именованных параметров, популярный фреймворк Grails и так далее. Но затем, в 2014 году, как будто никто не мог этого предсказать, вышла Java 8 с новой горячей функцией — лямбдами.
Лямбды устранили одно из самых значительных отрицательных замечаний о Java того времени — огромную церемонию анонимных внутренних классов для передачи поведения в коде. Или, проще говоря, в Java не было лямбд. Вскоре после этого, примерно в 2015/2016 годах, произошел значительный откат и падение Groovy. Сегодня его использование значительно сократилось, и никто даже не думает использовать его при создании новых сервисов.
Но инновации в экосистеме JVM не пропали вместе с Groovy, а совсем наоборот. Следующей блестящей горячей новинкой стала Scala!
Кто-нибудь помнит Scala?
Я помню! Я даже прошел курс на Coursera под названием «Принципы функционального программирования на Scala», который вел его автор Мартин Одерски. Честно говоря, Scala очаровала меня больше, чем Groovy. Самой большой фичей, которой мне не хватало в Java, было сопоставление шаблонов — навигация по сложным структурам данных без (зло)употребления шаблоном Посетителя с помощью простых лямбда-подобных выражений.
Было несколько сервисов Infobip, написанных на Scala, но они так и не прижились. Спад начался примерно в 2017 году, когда ушел один из ключевых мантейнеров языка.
Появление Kotlin
Следующим претендентом на то, чтобы «убить Java», стал Kotlin. Он медленно набирал обороты, но для меня он начал по-настоящему расти примерно в 2017 году, сначала когда был создан наш продукт People — бэкенд был написан на Kotlin, а затем когда наш родительский Maven был дополнен поддержкой Kotlin. Первый случай был важен как первое масштабное развертывание продукта Infobip с использованием Kotlin, а второй стал началом массового внедрения.
Плюсы Kotlin
Интероперабельность с Java
Хотя Kotlin не идеален, его совместимость с Java-кодом лучше, чем у его предшественников. Скорее всего, это связано с тем, что он появился после Groovy и Scala и смог извлечь уроки из их ошибок.
Кроме того, он не требует специализированных инструментов сборки (как sbt для Scala) и имеет плагины и интеграцию с IntelliJ. Тот факт, что он разработан создателем самой популярной IDE для Java, компанией JetBrains, является большим плюсом, но у него есть один огромный минус, о котором я расскажу ниже.
Корутины
Этот вариант действительно очень важен в экосистеме программного обеспечения Infobip. Он позволяет синтаксически дешево решить проблему масштабирования асинхронных задач. Особенно по сравнению с RxJava, Reactor, CompletableFutures и т.д.
До выхода Java 21 у Java не было замены этой возможности, но с выходом 21 и Virtual Threads она у нее появилась. Следующий год будет решающим в определении того, как она будет развиваться.
Если Virtual Threads окажется на высоте и снизит ценность перехода на Kotlin из-за корутинов, это ознаменует начало упадка Kotlin. Особенно если JetBrains не предложит новую крутую функцию, которая снова даст нам много пользы.
Структура данных и сопоставление шаблонов
До появления записей (records, 16) и сопоставления шаблонов (pattern matching, 21) Lombok был единственной альтернативой в Java.
Я не люблю Lombok больше, чем среднестатистический Java-разработчик, особенно потому, что он нарушает первое правило обработки аннотаций в Java — процессоры аннотаций не должны изменять .классы, сгенерированные компилятором Java.
Тем не менее, с учетом записей, я считаю, что в долгосрочной перспективе это лучшее решение, чем то, что предлагает Kotlin — особенно с учетом планов, которые в некоторой степени объясняются в этом обновлении языка Java (для полного контекста рекомендую посмотреть видео целиком).
В Java 21 сопоставление шаблонов имеет шаблоны типов и исчерпывающий характер, так что это один из плюсов, которого у Kotlin больше нет.
Работа с Null
Null всегда был подводным камнем в Java. Это немного улучшилось с появлением типа Optional. Именно поэтому я советую всем использовать везде только типы-обертки, а не примитивы, если только они не смогут доказать с помощью JMH-теста, что примитив дает достаточный выигрыш в производительности.
В Kotlin есть так называемая поддержка Элвис-оператора, который довольно популярен в современном дизайне языков для работы с null. Это лучше, чем вообще ничего не иметь, но может показаться довольно неэргономичным и странным при взаимодействии с системой типов языка. Я предпочитаю общий монадный подход с широко распространенными соглашениями о картах и плоских картах, а не посыпать свой код ?s
.
Самым большим недостатком Optional в Java является не его синтаксическая избыточность, а споры вокруг него, стоит ли вообще его использовать. Изначально он был создан почти исключительно для потоков Java 8, и мантра сопровождающих JDK «никто больше не должен его использовать» была очень вредной. В последнее время все больше людей из штата Oracle открыто заявляют, что Optional можно и нужно использовать везде, вместо того чтобы рисковать NPE, и яркий пример — здесь.
Я считаю, что они не хотели большого распространения и внедрения в дикой природе типов Optional<?>
, использующих Optional в качестве хранилища трех возможных наборов значений (null, Optional.of и Optional.empty), чтобы весь проект Valhalla value objects более просто справился с превращением Optional в инлайн-тип, не допускающий Null(это сломало бы весь код, использующий Optional, как уже говорилось). Это проще, чем потенциально ломать готовый код и настаивать на том, что он не придерживается Javadoc Optional.
Другие особенности
Другие возможности Kotlin, такие как синтаксис языка и расширения методов, не стоят упоминания. Привнесение особенностей в язык только для того, чтобы привнести их, может быть весьма вредным. Самый яркий пример — упомянутый ранее язык Scala, который, как и C++, предоставляет возможность перегружать операторы над типами. Подобные вещи делают код очень сложным для сопровождения, когда вы уже не можете с уверенностью предположить, что оператор делает то, что вы от него ожидаете.
Лучший пример — методы расширения. В корпорации, где предполагается, что каждая команда состоит в основном из джуниоров, затем мидлов, а потом сениоров, это очень опасно. Это может привести к большому количеству плохого кода, изобилующего ловушками для непосвященных. И еще одно замечание: если вы ожидаете, что кто-то пройдет ритуал посвящения, чтобы иметь возможность сопровождать кусок кода — вы не ведете себя как инженер-программист. Совсем наоборот — вы нарушаете этику программной инженерии! Код должен быть сопровождаемым, и это главная директива.
Минусы Kotlin
Интероперабельность с Java
Как первое «за» может быть и «против», спросите вы? Ну, вот официальное сообщение в блоге, которое рисует картину довольно четко. Цитируем:
Дальше все просто: мы ожидаем, что Kotlin будет способствовать росту продаж IntelliJ IDEA.
Теперь вы можете себе представить, почему IntelliJ IDEA, спустя столько лет, имеет возможность конвертировать Java в Kotlin, но не конвертировать Kotlin в Java. Это обычная практика, когда вендоры закрываются и извлекают большую прибыль — то, что снова стало популярным в 2023 году. Но я отвлекаюсь.
Экосистема Kotlin
Экосистема Kotlin сильно отстает от Java. FAANG имеет первоклассную поддержку и обязательства по отношению к Java, например, предоставляет JDK с многолетними обязательствами по поддержке.
Рабочая сила
По сей день разработчиков Kotlin значительно меньше, чем разработчиков Java.
Что это значит для компаний, использующих Kotlin? Более дорогая рабочая сила и препятствия в поиске людей для работы над проектами. Они могут подождать, пока кто-то появится на рынке, или начать переводить своих Java-разработчиков на Kotlin. Оба варианта стоят денег.
Отсутствие прогресса
По сравнению с Java в последнее время (например, записи два года назад, сопоставление шаблонов и выпуск VT в этом году), Kotlin застопорился в предоставлении больших возможностей, которые принесли бы нам (Infobip) преимущество над альтернативами. Для меня это самое большое беспокойство по поводу Kotlin, которое затмевает все остальные, упомянутые до сих пор.
Поиграем в адвоката дьявола
Факт остается фактом: нам нужен Kotlin. Зачем? Чтобы помогать нам исследовать, внедрять инновации и бросать вызов статус-кво.
Если Kotlin продолжит стагнировать и не появится новый крупный соперник с новыми крутыми функциями, которые повысят нашу эффективность поставке ПО, это станет проблемой. Для компании, у которой половина инфраструктуры, если не больше, написана на Java и работает только на JVM, переход на альтернативы вроде Kotlin гораздо дешевле, чем на Rust или Go. Нам нужны варианты и не стоит класть все яйца в одну корзину.
Мрачное будущее
Чтобы закончить эту запись в блоге, вот о чем идет речь в заголовке. В компании Infobip с 2017 года и до сегодняшнего дня идет золотой век Kotlin. Будет ли он продолжаться, зависит исключительно от JetBrains и их способности внедрять инновации в Kotlin. Переломным моментом станет 2025 год.
Почему именно 2025 год? В этот момент мы увидим, что на Java появляется все больше возможностей (например, проекты Valhalla и Panama), а альтернативы Kotlin не будет. Если к тому времени Kotlin не сделает значительный шаг вперед, его популярность упадет и достигнет критической точки. В сообществах разработчиков на YouTube, Hacker News или Reddit уже можно наблюдать движения в этом направлении, но пока оно не критическое.