Почему мы выбрали Kotlin одним из целевых языков компании. Часть 1: Ретроспектива

    Компания ДомКлик существует с 2015 года, и за это время мы успели сменить целевой язык для разработки ключевых сервисов с Java на Kotlin.

    Меня зовут Александр Коцюруба, руковожу разработкой внутренних сервисов в компании ДомКлик. Отвечая на вопрос, почему мы перешли на Kotlin, я опубликую два материала:

    1. Первая часть будет посвящена ретроспективе возникновения языка (которую вы, собственно, и будете сейчас читать)
    2. Вторая часть будет ориентирована на практически примеры (которая выйдет позже)

    Итак, начнем.

    image

    2010 год:


    • в августе проходит парад планет
    • в начале декабря в Цюрихе прошло объявление России как страны, принимающей чемпионат мира по футболу 2018 года
    • в конце декабря компания JetBrains выпускает Intellij IDEA 10.0

    Для JetBrains IDE — основной продукт, и они, как IT-компания, заинтересованы в быстром развитии и качестве своих продуктов. Разрабатывается Intellij IDEA на платформе JVM 6. С одной стороны, виртуальная машина отлично справляется с нагрузкой, надежна, как автомат Калашникова, и представлена внушительным сообществом. С другой стороны, развитие Java как языка начинает замедляться. Это связано в том числе с финансовыми трудностями в компании Sun Microsystems – языку банально начинают уделять меньше внимания, это видно из релизной частоты Java.

    Таймлайн релизов Java и Intellij IDEA:


    Как видно компания JetBrains успела выпустить шесть мажор-версий Intellij IDEA. В то время как Java продвинулось только на одну. Причем Java 6 не была большим прорывом, как, например, Java 5.

    На момент 2010 года Java уже достигла совершеннолетия (~20лет, старт разработки в 1990 году) и слегка «обросла мхом» в размере >50k классов. Со слов Андрея Бреслава abreslav, принимающего участие как внешний эксперт в разработке лямбд для Java, добавить такой функционал не нарушив работу JVM было достаточно сложно (одна из причин отложить релиз функционала в Java 8).

    Это сподвигло JB посмотреть в сторону других языков для разработки своих продуктов. В компании были компетенции по разработке на популярных на тот момент языках Groovy и Scala.

    От Groovy пришлось отказаться из-за недостатков динамически типизированных языков:

    1. Низкая производительность языка в runtime
    2. Высокая стоимость рефакторинга
    3. Отсутствие полноценной IDE

    Scala также не подошла для внутренней разработки JetBrains:

    1. Отсутствие полноценной IDE для языка
    2. Высокий порог входа
    3. Высокая стоимость разработчиков
    4. Производительность компилятора

    Стоит отметить, что Scala была удачным проектом с точки зрения совмещения разных концепций в одном языке.

    В то же время JetBrains при разработке той или иной среды разработки пишет фронтальный компилятор для соответствующего языка. Это включает в себя разбор семантического дерева, подсветку и т.п. Другими словами, описывает половину работы компилятора. Имея на тот момент 7 IDE, можно сказать, что компания JetBrains разработала 3.5 компилятора.



    Очевидно, что лаконичный код поможет сфокусироваться на бизнес-логике, что, в свою очередь, увеличит скорость разработки и уменьшит риск ошибки. Java 6 этому не способствовала, а жизнь самого языка и платформы была непонятна (отсылка к SUN и слухам продажи в Oracle Corp). Это подтолкнуло компанию к разработке языка под свои внутренние нужды.

    Ключевые требования к языку были следующие:

    1. Совместимось с Java (т.к. в компании большое количество кода уже было на Java)
    2. Лаконичность
    3. Быстрый
    4. Типобезопасность

    Так зародился проект под названием Kotlin.

    2010 — 2016:




    2012:


    К этому времени появляется MVP Kotlin.

    JB переводит Kotlin в статус opensource и начинает активно его использовать для внутренней разработки IDE. По результатам опыта внутреннего использования планируется решить, выпускать ли первый релиз продукта.

    2016:


    Выходит релиз Kotlin 1.0 с поддержкой JVM 6 и Android. В это время ДомКлик также пилотирует Kotlin и выпускает написанный на нем сервис безопасных расчетов – безналичный способ взаиморасчета за объект недвижимости между покупателем и продавцом. Разработчики довольны лаконичностью, возможностями и идеями языка и приняли решение включить Kotlin в список «дозволенных языков разработки».

    2017 — наши дни:




    2017 март:


    Выходит релиз Kotlin 1.1. Среди значимых фич стоит отметить:

    1. Поддержка JVM 8
    2. Корутины (экспериментальная версия)
    3. Компилятор в JavaScript

    Пару слов хочется добавить про компиляцию в JS. Учитывая опыт по разработке фронтальных компиляторов и потребности разработки, Kotlin практически с самого начала поставил перед собой задачу поддержки мультиплатформенности (Kotlin MPP, подробнее дальше в статье).

    2017 Ноябрь:


    Выходит релиз Kotlin 1.2. В релиз включают:

    1. Поддержка мультиплатформы
    2. Компилятор в нативный код (экспериментальная версия)

    Под поддержкой мультиплатформы подразумевается возможность подключения в проект модулей как специфичных для конкретной платформы, так и общих для платформ.



    В это же время Google включает поддержку языка Kotlin по умолчанию в Android Studio 3.0. На мой взгляд, это значимое событие для сообщества Kotlin, т.к. по сути язык получил признание со стороны Android сообщества в лице гиганта Google.

    2018:


    В октябре выходит релиз 1.3, включающий стабильные корутины с обратной совместимостью и компилятор в нативный код.

    В этом же году на архитектурном комитете в ДомКлике принимается решение о смене целевого языка разработки с Java на Kotlin.

    2019:


    В 2019 году для сообщества Kotlin происходит важное событие – все тот же Google на конференции устанавливает Kotlin как стандарт для разработки Android приложений.


    Весной 2019 мы достигаем переломной точки в смене Java на Kotlin. Наши графики показывают, что прирост функционала на Kotlin опередил Java. Другими словами, мы стали больше писать на Kotlin, нежели на Java, и наша ключевая компетенция де-факто сменилась на Kotlin.

    Наши дни:


    На сегодняшний день стоит отметить существование Kotlin for Data science. Данную тему хотелось бы осветить отдельно, погрузившись глубже и показав преимущества в следующих статьях.
    У нас же в компании на server-side доминирует Kotlin в сравнении с Java более, чем в 3 раза.

    В целом у нас в компании разнообразие языков программирования:


    Kotlin компиляторы:




    При помощи Kotlin MPP вы можете использовать Kotlin как дефолтный язык в разработке в своей компании. Мы в ДомКлике провели успешный пилот по разработке ипотечного калькулятора на Kotlin MPP для платформ Kotlin/JVM (Server-Side + Android) + Kotlin/Native(iOS). В дальнейших наших планах расширить пилот до Kotlin/JS.

    И подводя итоги.

    Первая часть статьи вышла теоритически-исторической, на то она и ретроспектива. Вторая часть будет ближе к практике, в ней мы рассмотрим на примере Kotlin/JVM:

    1. как он живет совместно с компилятором Java
    2. разберем несколько кейсов из Kotlin'a и как именно они отрабатывают на платформе Java.

    Полезные ресурсы:

    1. kotlinlang.org
    2. Доклад Андрея Бреслава — Что такое Kotlin? Введение
    3. Доклад Андрея Бреслава — Project Kotlin
    ДомКлик
    Компания

    Комментарии 33

      –2

      И даже на меня не сослался :( Я в печали. А ведь я как раз на опыте домклика (в основном) делал свой доклад про котлин в проде.

        0

        А оказывается просто не в этой части будет про меня. Тогда никаких обид.

        0
        Интересно бы увидеть таблицу для разных компиляторов (и их версий) для компиляции HelloWorld
        В которой будет количество Mb прочитанных с диска, использованной памяти, и общего времени выполнения.
        Что-то подсказывает groovy, kotlin и rust будут в «лидерах» по КПД.
        21+
        Вызов компилятора kotlinc из командной строки 6сек тот же swift 0.1сек.
        Ладно что большую часть это загрузка java rt.jar 62Mb на любой вызов.
        Но писать результирующие файлы по 1 байту за раз ???

        image
          +1

          Спасибо за репорт, пошёл спрашивать у коллег.

            +1

            Компилятор не пишет в .jar

              0

              Пишет если сделать так, чтобы писал. Я не думал что этим кто-то пользуется и никогда не пользовался сам, но…

              +3
              Что-то подсказывает groovy, kotlin и rust будут в «лидерах» по КПД.
              Не думаю, что кто-то сможет обогнать C++ :)
              А так, HelloWorld измерять бессмысленно, надо что-то реалистичное. А то это выглядит как «Попробуем перевезти мешок картошки на оке и белазе. Очевидно, у белаза, самый фиговый КПД, выводы делайте сами».
                +1
                Для тех кто в танке специально кавычки поставил. Даже C++ не выполняет столько бесполезной работы что бы скомпилировать hello world (пока не подключишь немного boost-а)
                ps: В эту же кучу еще надо отправить компилятор cuda который выполняет под капотом много чего что вызывает вопросы. (просто по наблюдайте за тем что появляется в директории %temp% пока оно компилирует)
                  +1
                  Даже C++ не выполняет столько бесполезной работы что бы скомпилировать hello world
                  Опять же к вопросу, как часто вы компилируете «hello world»? Это искусственная задача, в которой полезной работы исчезающе мало, по сравнению с ней любые накладные расходы будут «огромными».
                +1

                Как и обещал, возвращаюсь с ответом.
                Спасибо большое что сообщили о проблеме, мы завели по поводу её тикет https://youtrack.jetbrains.com/issue/KT-38176
                Не уверен что она будет исправлена прямо совсем скоро — всё-таки создание jar-файлов из kotlinc совсем нечастая операция и ни одна из поддерживаемых билд систем её не использует, однако же это не значит что она не должна быть исправлена.


                Ещё раз большое спасибо за репорт.

                  +1
                  А почему бы и нет
                  new BufferedOutputStream(new FileOutputStream(...
                  

                    +1

                    Ну мне тоже так кажется, но в принципе вы можете попробовать сделать PR с этим исправлением. А если ещё и бенчмарк будет там — то вообще офигенно.

                      +1
                      #!/bin/sh
                      
                      cat>test.kt<<'KT'
                      fun main() {
                          println("hello kotlin")
                      }
                      KT
                      
                      time -p kotlinc test.kt -include-runtime -d test.jar
                      
                        +1

                        Только вот на винде не выполнится )))

                          +2
                          Под виндой можно например так:

                          // test.c
                          #include <time.h>
                          #include <stdio.h>
                          #include <process.h>
                          
                          int main(int argc, char const *argv[]) {
                            int i; FILE *f; double dt; clock_t c1,c2;
                            enum { N=5 };
                          
                            f=fopen("test.kt","w+b"); if (!f) return 1;
                            fprintf(f,"fun main() {\n"
                              "  println(\"hello kotlin\")\n" 
                              "}\n");
                            fclose(f);
                          
                            for(i=1;i<=N;++i) { 
                              c1=clock();
                              if (system("kotlinc test.kt -include-runtime -d test.jar")) return 2;
                              c2=clock();
                              dt=c2-c1; dt/=CLOCKS_PER_SEC;
                              printf("%d\t%.2f sec\n",i,dt);
                            }
                          
                            return 0;
                          }
                          

                          tcc test.c && test
                0
                Автогенерируемые прекондишены когда можно будет отключать? Из-за них дорога котлина в интерпрайз будет закрыта.
                  0
                  Почему?
                    0
                    Потому, что их нельзя отключить. А это причина №1 почему миграция на котлин откладывается. Производительность приложения после миграции с java падает в 50-100 раз. Надо очень много допиливать ручками.
                      +1

                      Не может быть что из-за проверок на нал падает. Они джитом должны выпиливаться. Однако же если вы уверены что проблема именно в них, то есть -Xno-param-assertions -Xno-receiver-assertions

                        0
                        Да, вот именно их и не хватало. Надо будет заново протестить миграцию.
                          0

                          Они были как минимум с версии 1.1, вы просто не очень внимательно прочитали хелп.

                            0
                            Пожалуйста, дайте ссылку на официальную доку по этим параметрам.
                              0

                              Я, честно говоря, не знаю, есть ли дока по аргументам kotlinc, но узнать про все существующие параметры можно с помощью -help и -X -help, так же как в случае с javac

                                0

                                Вот, в официальной доке сказано что больше параметров можно получить с -X: https://kotlinlang.org/docs/reference/compiler-reference.html#-help--h

                          0

                          Если можно, очень хотелось бы посмотреть на код бенчмарков и какой-нибудь минимально воспроизводимый пример. Потому что если существует какой-то кейс, при котором проверки на налл реально тормозят находясь на горячем пути — мне бы очень хотелось о них знать.


                          То, с чем я встречался — это что java2kotin генерирует неоптимальный код, но с этим особо ничего не сделаешь — оптимальный код доменно-специфичен.

                      +3
                      При помощи Kotlin MPP вы можете использовать Kotlin как дефолтный язык в разработке в своей компании.

                      Можно ли это делать без знаний Java и её экосистемы в компании? Не получится ли, что компания (или отдельный разработчик), решившие сделать для себя Kotlin дефолтным язык в итоге 80+% времени потратят на изучении и внедрение не Kotlin, а Java? Что, грубо говоря, отдельный Kotlin-разработчик, никогда на Java не писавший, уже на 90% Java-разработчик?


                      P.S. Кстати, есть какие-то книги, курсы и т. п. по обучению разработки на kotlin, не подразумевающие знания Java? Или как 90+% книг и курсов на TypeScript: "Typescript — это JavaScript, но с типами. Вот эти типы мы и будем изучать в рамках этого курса"

                        +2
                        Ну не 80%, но немного потратят. У меня как раз есть опыт работы с kotlin на бэкенде без знания java. Сам котлин и его фишечки с корутинами и каналами как в Go очень приятные.
                        Код получается лаконичный. Но когда нет опыта с java world, случаются нежданчики.

                        Ставишь простой с виду логгер. А как его тюнить — хз, нет опции в конструкторе типа «конфиг». Потом оказывается, что нужен как-то xml файл с конфигом для логов «как обычно». И начинаешь гуглить, как так получилось, что логгер который «чисто на котлине», на самом деле обертка над оберткой и еще над оберткой, и почему ему нужен какой-то xml конфиг в каком-то правильном месте.
                        Для тех, кто с java знаком, тем все очевидно.
                        Или работа с датой временем. Есть joda.Time, есть еще java.Time. И если какая-то сторонняя либа использует только joda.Time, а ты везде используешь jave.Time, то пиши переходник. И поначалу непонятно, какого огурца вообще происходит и зачем нужны 2 либы для работы со временем.

                        Это все нюансы java world, которых там много, но их как-то быстро преодолеваешь и потом нормально.
                          +1

                          Kotlin MPP связан с джава экосистемой примерно никак. Стандартной библиотеки джавовой в нём нет, по сути только базовые типы. Остальное можно добрать сторонними библиотеками.

                            0

                            А как насчёт управления библиотеками (пакетными менеджерами), системами сборки, вон про конфигурирование выше пишут, особенно в случае использовании для классического HTTP REST бэкенда

                              0

                              Управление библиотеками, сборкой, тестами — gradle. Но писать бэкэнд на MPP кажется странным, как раз тут лучше получится обычный Kotlin/JVM, мне кажется.

                                0

                                Я в разнице не разбираюсь. Что в статье написано, то и процитировал :) Может там что-то имелось в виду типа "на фронте/мобайле Kotlin MPP, а на бэке "голый" Kotlin", но сути моего вопрос это не меняяет: если взять фулстека, который существующий стэк (пускай PHP+TS) переводит на Kotlin MPP/Kotlin, то не получится ли, что 80+ % времени он будет заниматься по факту изучением Java и её экосистемы, а лишь 20%- собственно Kotlin

                                  0

                                  О, такого опыта у меня нет, к сожалению, не буду комментировать.

                          0

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

                          Самое читаемое