Kotlin после Groovy

Привет!

Хотелось бы сегодня рассказать про мой процесс перехода с Groovy на Kotlin, об отличиях, преимуществах и недостатках этих языков. Я подразумеваю что у вас уже есть опыт работы с Groovy, вы знаете и используете большинство вспомогательных методов/приемов (далее сахар).

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

Как многим, наверное, известно, в большинстве случаев Groovy работает медленнее Java. Единственный способ сделать Groovy сравнимым по скорости с Java — это @CompileStatic. Но, если вы работали с Groovy и у вас накопилось достаточно много Groovy кода, где вы не гнушались использовать все прелести динамической типизации, как в примере ниже, то у вас не получится просто взять и расставить везде @CompileStatic, придется переписывать много кода.

def map = [:]
map["a"] = 5
def a = map.a

И, практически, это превращает Groovy-код в статически типизированный. И писать на нем становится не так приятно.

В то же время, Kotlin статически типизированный из коробки. Вам не нужно ничего дополнительно писать, чтобы Kotlin код компилировался и работал так же быстро, как и Java-код. То есть, простыми словами, если написать компилируемый, рабочий код на Java, Kotlin и Groovy, и запустить его, не парясь с оптимизациями, то мы увидим, что скорость Java и Kotlin будет на одном уровне, а Groovy проиграет в несколько раз.

Это была одна из основных причин перехода на Kotlin. Кроме того, мы столкнулись с тем, что в некоторых местах нашего приложения у нас слишком много динамической типизации и становится практически невозможно работать с такими данными. К примеру, у нас есть Map, в которой содержатся объекты разных классов, в некоторых из них тоже лежат Map со всякими разными данными, и все это может генерироваться в 3 разных местах. И чтобы понять, что на самом деле содержится в объекте, и какие у него вообще могут быть состояния уходит очень много времени.

Самое смешное, что изначально все классы были красивыми, чистыми (иначе их бы не пропустили на code-review), но, со временем, мы добавляем 1 поле, потом еще 1, потом вроде бы уже стоит сделать рефакторинг, но времени нет и постепенно простая структура обрастает кучей лишних полей, данных и возможных состояний. И бороться с этим в динамически типизированном языке очень сложно.

И последняя причина перехода на Kotlin — он просто модный и молодежный 🙂

Итак, я уже больше года пишу разрабатываю на Kotlin. До этого 3 года писал на Groovy. Чистую Java практически забыл 🙂 Рассмотрим преимущества и недостатки Kotlin в сравнении с Groovy, с точки зрения разработчика.

Преимущества Kotlin

  1. Статическая типизация. В любой момент времени мы точно знаем тип каждой переменной. Если это не так — компилятор упадет с ошибкой.
  2. Скорость компиляции и выполнения, сравнимая с Java.
  3. Еще более строгая типизация, в сравнении с Java. Nullable/notnullableтипы, mutable/immutableколлекции, мапы и т.д. Это позволяет еще больше контролировать свой код. Ты можешь просто взглянуть на тип (или спросить IDE) и ты будешь знать возможен ли там null, может ли кто-нибудь добавить что-нибудь в коллекцию и т.д. Для этого больше не нужно искать все использования.
  4. Удобнее пользоваться функциями (они же лямбды, они же closure), т.к. нам точно известно, что функция ожидает на вход и что она вернет
  5. Присутствует большая часть сахара из Groovy
  6. Классы, поумолчанию, final.
  7. Встроенные Singleton объекты (object BlahBlah{ … })

Недостатки Kotlin

  1. Нельзя быстренько налепить костылей. Например, нам нужно вернуть 3 разных объекта, в Groovy мы можем вернуть Map с тремя этими объектами и забыть. В Kotlin придется или сразу писать чистый код, или создавать класс.
  2. Бывает сложно написать шаблонный класс. Из-за строгой типизации нужно очень внимательно сделать за параметрами шаблонного класса, особенно когда случай не тривиальный.
  3. Новичкам сложно начинать писать на Kotlin, т.к. он требует писать код однозначно и аккуратно. Особенно новичкам сложно с nullable/not-nullable типами.
  4. Странным образом реализован аналог статических методов/полей. По сути, в Kotlin нет статических методов/полей, можно создать объект-компаньон-синглтон, в которые необходимо перенести все то, что было бы статическим в Java или Groovy
  5. Из-за того, что все классы по умолчанию final — есть проблемы с тестированием. Чтобы мокать такие классы необходимо либо помечать их как open, либо использовать новые библиотеки для тестирования, которые умеют мокать final классы.
  6. Интеграция Kotlin кода в Java/Groovy — не очень удобная. Не работают параметры по умолчанию, методы, которые находятся в объекте-компаньоне необходимо помечать аннотацией @JvmStatic. Расширения классов запускать тоже не очень удобно (пример ниже)
//Допустим у нас есть такое расширение для String
fun String?.isValidPhoneNumber() = this != null && this.isNotEmpty() && ...

//В Kotlin коде его можно использовать так:
val string = "+79998887766"
string.isValidPhoneNumber()

//Но в Java/Groovy придется использовать следующую конструкцию
def string = "+79998887766"
FilenameKt.isValidPhoneNumber(string)

P.S.:

Пока писал этот пост, вспомнил, что часто сталкиваюсь с ситуацией, когда мне заранее точно известно, что коллекция/мапа обязательно должны быть не пустыми. Сейчас в Kotlin доступны вспомогательные классы/типизация для mutable/immutable nullable/not nullable коллекций. Я думаю, не пустая коллекция тоже бы пригодилась

Поделиться:

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

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте как обрабатываются ваши данные комментариев.