Когда кто-то смотрит на код Corda, то сразу обращает внимание, что он написан на Kotlin — новом языке программирования от JetBrains, который может компилироваться под JVM и в Javascript. Это был необычный выбор, и в этой статье я хочу поделиться некоторыми причинами такого решения и опытом нашего "года с Kotlin в продакшене".
Почему Kotlin?
Данное решение можно разделить на две части:
- Какую платформу использовать? JVM, .NET, Node, Python/Ruby, Go, Haskell или что-то компилируемое (в машинный код)?
- Какой язык использовать, если выбрали JVM? Java? Если — нет, то почему? И если — нет, то какой другой: Scala, Ceylon, Clojure, Kotlin, Python, Ruby, Javascript или Haskell (т.к. все они имеют реализацию для JVM).
Причины выбора JVM в качестве платформы хорошо известны в среде корпоративных приложений и нет большого смысла останавливаться на этом. Достаточно будет сказать, что если вам нужна масштабируемая, потокобезопасная, кроссплатформенная среда выполнения со сборкой мусора, и с множеством хорошо документированных библиотек, решающих основные бизнес-задачи, то выбор уже сводится только к JVM и .NET.
В начале работы над Corda проект не имел названия и трудно было представить, что в дальнейшем он разовьется в продукт. На самом деле когда проект, ставший Corda, начался в декабре 2015 (в мой первый день на работе), в планах не было создание новой корпоративной распределенной учетной системы. Corda начался в виде набора прототипов для исследования новых идей и требований, в которых была заинтересована Рабочая группа по архитектуре (Architecture Working Group) консорциума, в особенности связанными с ограниченной видимостью данных и моделью данных обеспечивающей масштабируемость "массива неистраченных выходов транзакций (UTXO set)" наряду с программируемостью (programmability) императивных смарт-контрактов Ethereum в целом.
По причине того, что не было ясно превратятся ли эти прототипы во что-то, или просто послужат в качестве информации для других продуктов на рынке, перед нами встал непростой выбор. С одной стороны, мы хотели быстро и продуктивно исследовать алгоритмы и структуры данных. С другой, должна оставаться потенциальная возможность создания крупного корпоративного продукта и быстрого найма людей под него.
Java определенно отвечала этим требованиям, но отсутствие в языке современных возможностей значительно снижает продуктивность, и, что более скрыто, боевой дух разработчиков.
Динамическая типизация не рассматривалась — польза от корректности, инструментов разработки и производительности, обеспечиваемых статической типизацией, слишком велика чтобы ей пренебречь.
Языки, в корне отличающиеся от наиболее популярных, также не рассматривались, т.к. мы хотели иметь возможность найма экспертов в финансовой сфере. И, хотя, создание команды вокруг языка подобного Haskell вполне возможно, поиски человека с серьезным опытом в банковской сфере и ленивых (lazy) чистых (pure) функциональных языках случайно проживающего в Лондоне казались рискованными. Вдобавок, сама природа продукта подразумевала, что наши "пользователи" на самом деле разработчики плагинов и приложений, которые используют платформу, и нет смысла требовать от них изучения совершенно новых парадигм и инструментов. Наш выбор языка не должен слишком ограничивать пользователей.
В результате эти требования оставили нас с Kotlin, Scala и Ceylon. Эти языки довольно схожи и достаточно интересны. Мы выбрали Kotlin по следующим причинам:
- Практически бесшовная интеграция с Java
- В особенности, программы на Kotlin используют улучшенную (compiler-enhanced) версию стандартных коллекций JDK, что, таким образом, обеспечивает отсутствие проблем интеграции из-за использования других библиотек коллекций. Мы повсюду передаем и получаем коллекции в и из Java-библиотек, поэтому важно чтобы это не вызывало проблем.
- Из Kotlin-классов получается обычное на вид Java API с методами
get
/set
/is
в соответствии с типами. Особые аннотации или другие действия для этого не требуются. По той причине, что Corda предоставляет, предназначенное для прозрачного использования Java-разработчиками, API — это большое преимущество: из обычного кода получается API, которое невозможно отличить от Java API лишь с несколькими оговорками (например, для возможности перехвата проверяемых исключений из Java требуется явное аннотирование методов)
- Встраивание (inlining) маленьких функций, подобных
map
/filter
/fold
/groupBy
(вместо надежды, что JVM сделает это сама), выполняется компилятором. К сожалению, JIT компилятор JVM, хотя и превосходный в целом, не во всех случаях устраняет накладные расходы обильного использования функций высшего порядка. Использование Kotlin это компенсирует, вдобавок позволяя управлять выполнением программы изнутри лямбда-функций (примечание: например, non-local return). Это одна из малоизвестных, но, при этом, полезных возможностей. Т.к. мы везде пишем код в таком функциональном стиле, то, если бы он плохо транслировался в машинный код, мы могли создать себе проблемы с производительностью. - Из-за того, что код на Kotlin транслируется в достаточно схожий Java-код, практически все существующие Java-ориентированные инструменты работают из коробки. Это не всегда правда в случае других языков. Например, Quasar с трудом инструментирует код на Scala из-за того, что ему необходимы аннотации методов, а Scala транслирует лямбды в методы, которые невозможно аннотировать. Лямбды Kotlin обычно встраиваются (см. выше), или могут быть аннотированы в противном случае.
- Превосходная документация и крошечная стандартная библиотека делают его изучение очень быстрым. Мы не указывали в наших вакансиях необходимость опыта на Kotlin, и нанимали людей без его знания давая на раскачку 1-3 дня после которых новый член команды был в состоянии писать идиоматичный код.
- Исходя из выбора кандидатов, проходивших у нас собеседования, IntelliJ является наиболее популярной IDE (у них был свободный выбор инструментов). Среди пост-Java языков IntelliJ поддерживает Kotlin лучше всех.
- У меня уже был с ним удовлетворительный опыт работы, и, поэтому, я был уверен, что новым коллегам он, также, понравится.
Если бы не было Kotlin мы, вероятно, выбрали Scala: Kotlin во многом вдохновлен им и оба являются хорошими языками.
Наш год с Kotlin
Каково это — год работать с новым языком в контексте корпоративного приложения?
Самым главным было, без сомнения, услышать от коллег, что им очень нравится с ним работать. Язык программирования личное дело каждого, и люди, обычно, имеют определенное мнение на этот счет. Если вы, в качестве первой задачи на новой работе, просите кого-то изучить новый язык и даже не предупреждаете об этом заранее, то всегда есть риск, что коллега его просто возненавидит и скорее найдет раздражающим, а не повышающим его продуктивность. Но это не тот случай.
Ниже приведены некоторые проблемы, которые зачастую всплывают в пост-Java/C# среде корпоративной разработки, и с которыми столкнулись мы сами:
- Код выглядит по-разному в зависимости от того кто его написал. В общем и целом не такая уж и большая проблема. В отличие от Go, который требует определенного стиля оформления, Kotlin-код разных авторов может выглядеть по-разному. Но у IntelliJ есть инструмент форматирования, который обеспечивает унификацию стиля кодовой базы. Он более ограничен, чем для Java, но этого достаточно. Более тонкой проблемой, особенно с кодом на Scala, является противостояние Java-ООП и Haskell-ФП стиля кодирования. Scala-код, в котором используются такие библиотеки как scalaz, может оказаться трудным для чтения для разработчиков, которые ожидали увидеть улучшенную Java. В этом споре Kotlin довольно твердо стоит на стороне улучшенной Java. И, хотя, функциональное программирование, в определенном виде, возможно и на Kotlin, сообщество (по крайней мере пока) не раскололось на лагеря. У нас были случаи когда код был написан так как будто это Haskell, но это прорабатывалось на codereview.
- Библиотеки. В Corda мы используем более 50 библиотек с открытым исходным кодом и проблем не было ни с одной. Мы никогда не писали обвертки или слои адаптеров. В качестве систем сборки в проектах на Kotlin, обычно, используются Maven или Gradle — нет какой-то официальной специфичной для Kotlin замены этим инструментам (хотя Gradle внедрил поддержку Kotlin в качестве нового языка сценариев!).
- DSL-и SQL. У C# есть LINQ, у Java — JOOQ, а у Kotlin — Exposed. Это одна из областей где Kotlin несколько слабее конкурентов — Exposed является прекрасным примером использования возможностей Kotlin для построения DSL, но сама библиотека имеет нестабильное API и является второстепенным проектом. JOOQ, конечно, можно использовать и с Kotlin, и, оглядываясь назад, это кажется более предпочтительным вариантом.
- IDE/инструментарий. Kotlin-плагин для IntelliJ, конечно же, написан JetBrains и, в целом, великолепен. Однако, он менее изощрен в сравнении c поддержкой Java. Новые возможности редактора, такие как подсказка параметров, должны быть вручную портированы для Kotlin, и сама поддержка, как таковая, обычно отстает для гораздо более старых Java-плагинов. Также мы заметили, что плагин IDE довольно часто уведомляет о внутренних ошибках, хотя частота исключений IDE в течении года значительно снизилась (и, кажется, они не влияют на что-либо). Использование других инструментов также не вызывает проблем, т.к. то, что написано для Java, обычно, работает из коробки. Исключением являются инструменты работающие с исходным кодом вместо байткода, и которые, что очевидно, невозможно переиспользовать. При всем этом, компилятор Kotlin и плагин IDE не так отлажены как в случае Java даже спустя год после релиза 1.0. Скорее всего вы никогда не столкнетесь с внутренними ошибками в
javac
, но, хоть и очень редко, мы до сих пор встречаем их в Kotlin. - Признание пользователями. Пользователи Corda это, чаще всего, крупные и консервативные финансовые структуры. Такие компании предпочитают использовать распространенные, устоявшиеся языки. Kotlin, не будучи ни тем ни другим, явно вызывал некоторое удивление в то время когда мы начинали. "Почему Kotlin?" — это вопрос, который, в течение прошедшего года, практически исчез, т.к. люди присмотрелись поближе и осознали, что это не так рисковано как обычно бывает с новыми языками программирования. Также мы старались способствовать принятию предоставляя примеры кода демонстрирующие, что создание приложений с использованием платформы не требует знания Kotlin. Результаты этого были не такими успешными — многие разработчики, впервые работающие с Corda, до сих пор начинают со знакомства с Kotlin. Не очень понятно является ли это результатом того, что мы предоставили недостаточно Java-ориентированных примеров использования и документации, или это просто хорошее оправдание изучению нового классного инструмента. Нам, также, помогло возрастающее принятие Kotlin внутри крупных инвестиционных банков. За прошедший год мы слышали от нескольких членов консорциума, что их внутренние команды разработки начали всерьез посматривать на Kotlin для собственных продуктов: часто стимулируемые наличием инструментов, конвертирующих Java в Kotlin, которые обеспечивают значительно менее болезненную интеграцию в существующую кодовую базу.
- Коммерческая поддержка. Риск использования малоизвестных языков заключается в том, что они могут перестать развиваться, или иметь цели, которые не согласуются с потребностями, образовавшегося вокруг продукта, сообщества пользователей (например, в случае исследовательских языков, главной целью разработчиков является создание научных статей). Основной причиной, из-за которой мы чувствуем уверенность с Kotlin, является то, что JetBrains — это стабильная, прибыльная компания, которая находится на рынке уже более 15 лет. JetBrains быстро стали пробовать на вкус собственный инструмент внедряя Kotlin в код основных продуктов. Таким образом, риск прекращения поддержки довольно мал. Вдобавок JetBrains — уже немолодая компания, и её целевой рынок (IDE и инструменты для разработчиков) перестал быть новым или особенно модным, что снижает риск возможного поглощения компании, который может привести к непредсказуемым стратегическим изменениям. И, несмотря на отсутствие для Kotlin пакета коммерческой поддержки, на практике команда достаточно быстро исправляет известные проблемы. На данный момент JetBrains намерены выпустить следующее обновление языка после года с выпуска 1.0. Такой релизный цикл достаточно схож с циклом разработки в корпоративной среде.
Выводы?
Мы не сожалеем: выбор молодого языка на старте этого проекта был хоть и риском, но взвешенным. Он хорошо поработал для нас и мы бы не изменили свой выбор.
Автор: semyong