Два года с Dart: о том, как мы пишем на языке, который ежегодно «хоронят» (часть 1)


    «А он еще не умер?»,- спрашивают нас про Dart на каждой фронтенд-конференции. «А как Google поддерживает язык?», «как вы нанимаете разработчиков в команду?», «а почему не TypeScript, если вам нужна типизация?»

    Мы решили объединить наиболее частые вопросы и задать их в интервью Игорю Демьянову, менеджеру по разработке Wrike.

    Поговорим с ним о том, почему Wrike, с 2 млн строчками кода за спиной больше двух лет назад не побоялся перейти с JavaScript на Dart, как проходила миграция, как рос продукт и увеличивалась команда разработчиков, как развивается язык сегодня, несмотря на разговоры о его стагнации или даже смерти.

    Игорь, продукту уже больше 10 лет, а что было до того момента, как вы начали использовать Dart для разработки фронтенда Wrike?

    До Dart мы писали на ExtJS 3 и частично на ExtJS 4. Плюс у нас был небольшой самодельный фреймворк, который написал один из бывших сотрудников. Этот «велосипед» нам сейчас скорее мешает, и мы от него потихоньку избавляемся. На данный момент в проекте более 2,5 млн строк клиентского кода, новый функционал мы уже года два пишем на дарте и потихоньку избавляемся от легаси на ExtJS.

    В какой момент и почему пришло понимание, что надо переставать писать на JS?

    Оно пришло, когда Wrike начал активно расти. Когда у нас в команде было 11 человек — мы еще как-то могли использовать JavaScript, более-менее понимать, кто какой код пишет, помнить все нюансы старого кода. Но сейчас в команде фронтенда у нас около 50 человек, разработчики распределены более чем по 10 scrum-командам, и правило личных договоренностей уже не работает. Задач много, разработчиков много, кода много.

    Много кода — это сколько?

    На клиент мы в данный момент грузим около 10 мегабайт сжатого кода, раньше было 5 или 6. И раньше эта цифра выглядела страшно, сейчас и подавно. Но мы тут ничего не можем сделать -продукт активно растет функционально. Разумеется, мы стремимся, чтобы отдельные куски кода грузились по требованию, но в каких-то случаях приходится подгружать весь код сразу, чтобы весь функционал Wrike был доступен клиенту мгновенно.

    Так а почему Dart?

    Dart выгодно отличается от всего остального тем, что он может выкидывать неиспользуемые части кода, это и позволяет нам жить с таким огромным легаси. Когда проект большой и разработчиков много, очень сложно контролировать, что ты используешь, а что нет. Есть код, который лежит в кодовой базе — может быть, его просто кто-то забыл выкинуть из общей сборки — и он все еще живет с нами. И если бы мы использовали JS с его сборщиками, этот код точно приходил бы на клиент. А Dart позволяет оптимизировать и выпилить ненужный код. Плюс мы не зависим ни от каких стандартов JS, которые постоянно меняются и обновляются. Кода ты делаешь enterprise-продукт, очень сложно выбить у бизнеса время на перевод с одного стандарта на другой.

    Выбрав Dart, мы пошли по пути медленной миграции: вначале переписали корную часть, затем — остальной функционал. Сейчас у нас уже грузится нового кода больше, чем старого. При этом продукт активно развивается и новые фичи приходится делать очень быстро.
    С точки зрения команды, процесс тоже поменялся — разработчики меньше времени тратят на разбирательства, какие параметры куда передаются.

    Да, сейчас примерно эти же возможности есть у Typescript или JS+Flow, но нам нравится Dart. У языка простой и понятный синтаксис, а главное — он позволяет нам концентрироваться на идеях, экономить время, которое бы мы тратили на рефакторинг или, скажем, на переход с ES5 на ES6, фреймворки и т.п.



    Сейчас ведется какая-то разработка компонентов продукта на JS?

    В отдельных исключительных случаях мы можем вносить изменения в легаси-код на JS, если видим какой-то critical bug. В остальных случаях пишется новый код на Dart — он либо заменяет старый код, либо добавляет новый функционал.

    Какой фреймворк вы используете?

    Примерно год назад мы перешли с Polymer на Angular2. Сейчас планируем переход на Angular3, а к концу года — на Angular4. Во многих компаниях бизнес в этом отношении довольно тяжело идет навстречу R'n'D — такие миграции сопровождаются долгими спорами и убеждениями. То, что мы используем самые новые инструменты — не только заслуга фронтенд-разработчиков, но и наших тестировщиков-автоматизаторов, которые хорошо помогают нам с регрессионными тестами и QA Manual. Когда мы переходили на Dart, то получили поддержку всех технических команд Wrike, поэтому этот переход нам дался относительно безболезненно. Так же и с Angular — прогнозируем, что переход между версиями затянется на 1-2 месяца, вряд ли больше.

    Сейчас мало знают о языке Dart, но 2 года назад информации же вообще не было. Как вообще вам удалось по живому в работающем проекте все переделать? Трудно представить, что бизнес на это вообще пошел.

    Я сам начал использовать Dart с версии 0.8, когда он был еще только в бете. На момент внедрения в Wrike Dart уже был официально зарелижен, появилась спецификация, стандарты и т.п., то есть мы были уверены, что принципиально в языке ничего не будет меняться. Мы знали, с каким языком будем иметь дело, все проанализировали и получили первые результаты, которыми смогли аргументированно доказать необходимость изменений. Главным доводом в пользу дарта был Tree Shaking — умение дарта выпиливать неиспользуемый код вплоть до методов. А это при нашем объеме legacy критично.

    Почему не TypeScript?

    Если бы мы, допустим, портировали Wrike на TypeScript, это было бы, наверное, «дешевле». С другой стороны, у нас столько кода, что портирование на TS, нам скорее всего ничего бы не дало — остался бы тот же объем подгружаемого легаси, только на TypeScript. Dart же заставляет нас писать лаконично и правильно, и не дает допустить простых ошибок в проектировании, это его плюс, но в этом, конечно, и его строгость.

    Если вернуться к бизнесу, то да, здесь мы получили поддержку. Наш CEO Андрей Филев — сам в прошлом разработчик, и разговор с ним можно вести на одном языке. Плюс, репутация Google как разработчика языка о многом говорит. В конце концов, эти изменения были необходимы и самому бизнесу, чтобы максимально быстро разрабатывать и выпускать фичи, позволяющие нам оставаться одними из лидеров рынка. В общем, бизнес поддержал, и сейчас мы очень быстро движемся, а бизнес доволен нашей скоростью.

    Но вот те 11 человек, которые писали на JS и вынуждены были переходить на Dart, наверно, не так радостно восприняли эту новость?

    Ребята, которые поработали с каким-то другим языком, кроме JavaScript, очень легко переходили на Dart. Они, наоборот, были довольны, что дарт решает их проблемы с чужим кодом и упрощает коммуникацию. Конечно, были и те, кто знал только лишь один JavaScript, и, как и любой «старовер», в штыки воспринимал изменения.



    Сейчас в JavaScript-мир довольно низкий порог вхождения, очень много в сообществе новичков, которые осваивают язык, но едва ли понимают, как проектируются большие продукты. У моего коллеги Евгения Гусева есть доклад на эту тему, который не так давно вызвал немалую полемику среди JS-разработчиков.

    Любой язык можно рассматривать только в контексте его применения, поэтому тут споры и холивары бессмысленны. Например, JavaScript всем хорош для прототипирования — как бы вы ни написали код на JS, вы его скорее всего запустите. Нет понятия “плохой JavaScript” — либо он работает, как вам нужно, либо он работает не так, как вам нужно, и все.



    С Dart сложнее. У вас, как в Java и как в .net, есть анализатор, который вам говорит: «Знаешь, дружок, как бы не так. Так нельзя делать. Нельзя создавать динамические классы и т.п.». То есть язык просто не позволит самому себе выстрелить в ногу, как бы вы ни хотели.

    Если вы посмотрите, многие создатели Dart, работали с серьезными объекто-ориентированными языкам, V8 делали, даже кто-то из Java у них есть. Они подошли к проектированию языка с точки зрения больших приложений, поэтому Dart – это язык для средних, больших, и очень больших приложений. Он по дефолту предлагает одно, но самое эффективное решение, и оно идет «из коробки». Вы в один клик можете сделать отложенную загрузку/загрузку по требованию, язык сам будет «выпиливать», оптимизировать код – это те бонусы, которые нужны большим приложениям. На маленьких приложениях вы практически никакого заметного эффекта по сравнению с JS не увидите.

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

    Мы будем благодарны за вопросы в комментариях и, если потребуется, напишем более подробные технические статьи о работе с Dart на их основе.
    Wrike 80,40
    Wrike делает совместную работу над проектами проще
    Поделиться публикацией

    Вакансии компании Wrike

    Комментарии 49
    • +1
      Angular3. Когда еще не знаешь что Angular 4
      • +1
        Версионность в Dart версии и в TypeScript версии отличается.
        В TypeScript они просто третью версию перескочили.
        • –1
          Тогда не Angular a AngularDart
          • 0
            Так в статье речь и идет о Dart
        • 0
          Это назвается К — Консистентность. Команда AngularDart решила не перепрыгивать через версию, в отличие от TS команды
        • –3
          > Сейчас планируем переход на Angular3, а к концу года — на Angular4

          Angular 3?
          • +1
            См. ответ выше. В Dart версии Angular своя кодовая база и своё версионирование, не привязанное к Angular на TypeSctipt.
            • 0

              Для Dart есть свой Angular, вот тут: https://github.com/dart-lang/angular2
              И у него последняя версия действительно 3.

            • +1
              Polymer сейчас тоже активно развивается, почему решили перейти на Angular2? В вашей компании есть опыт совместного использования обоих инструментов?
              • 0
                Мы юзали Polymer (тогда ещё 0.5 версии). После выхода версии 1.0 использовать его стало невозможно. В целях «оптимизации» оттуда выкинули очень много всего. В итоге перешли на Angular,
                Последнюю версию Polymer ещё не пробовали, но сильно сомневаюсь, что он побъёт Angular по богатству фичей, всё таки это скорее библиотека компонентов + шаблонизатор
                • 0
                  Потому что решили использовать Polymer, т.к. «стильно, модно, от Google», а потом оказалось, что он тормозной, более-мене работает в Chrome, а в стабильной версии (1.x) и убрали многие фичи к тому же.
                • НЛО прилетело и опубликовало эту надпись здесь
                  • +1

                    На всякий случай добавлю, что у webpack тоже есть tree shaking с ES6 модулями (если используется babel, нужно в конфиге отключить трансформацию импортов/экспортов), да и google closure compiller тоже вроде как умел в такое.

                    • 0

                      Тут есть принципиальное различие: Tree shaking на уровне модулей это типа


                      // a.js
                      class A {
                        someMethod() {
                          //...
                        }
                      }
                      
                      class SomeVeryBigClass {
                          //...
                      }
                      
                      export {
                        A, SomeVeryBigClass
                      }
                      --------------------------
                      // b.js
                      export class B {
                          anotherMethod() {
                             //...
                          }
                      }
                      -------------------------
                      // c.js
                      import 'a.js'
                      let a = new A();

                      В случае "модульного" перетряхивания модуль b.js не будет подключен. Однако все классы из модуля a.js будут присутствовать, внезависимости от того, используются ли они или нет.


                      Что же Dart?


                      // a.dart
                      class A {
                        someMethod() {
                          //...
                        }
                      }
                      
                      class SomeVeryBigClass {
                          //...
                      }
                      
                      -------------------------
                      import 'a.dart'
                      main() {
                          var a = new A()
                      }

                      В случае Dart перетряхивание уберёт не только класс SomeVeryBigClass, но и someMethod из класса A, так как он не используется.
                      Итого разница — Tree Shaking в Дарт более гранулярный, он может убирать всё, вплоть до методов и свойств класса.

                      • НЛО прилетело и опубликовало эту надпись здесь
                      • НЛО прилетело и опубликовало эту надпись здесь
                        • 0
                          Ну а есть какая-то статистика по проекте, сколько в итоге этот Tree Shaking кода выпиливает? Из всяких Ангуляров и прочих зависимостей, и собственного кода?
                          • 0

                            К сожалению самой свежей инфы нет. Сейчас в планах перейти на Dart 1.24, он делает более эффективную компиляцию в JS. Тогда и обновим данные

                      • 0
                        Не совсем понятно — компоненты ExtJS чем заменили? Или все виджеты с нуля переписали?
                        • 0

                          Сейчас легаси живёт вместе с AngularDart, бОльшую часть уже переписали, да.

                        • +2
                          Dart заставляет нас писать лаконично и правильно
                          А Typescript заставляет писать объемно и криво, подталкивает к ошибкам при проектировании?..

                          Я прочитал параграф про «Почему не Typescript» два раза, но ответа на вопрос так и не нашел. Судя по всему, объективной причины нет и просто «так сложилось».
                          • 0

                            Typescript все-таки является расширением Javascript. Грубо говоря, можно переименовать файл js -> ts, и код все равно будет собираться.


                            Dart это совершенно другой язык, со своей парадигмой. Писать в Javascript-стиле на нем не получится. Поэтому можно сказать, что на Dart код получится "правильнее".

                            • +1
                              Грубо говоря, можно переименовать файл js -> ts, и код все равно будет собираться.
                              Если задача — не дать разработчикам схалявить, то можно включить жесткие проверки компилятораnoImplicitAny, noUnusedLocals, allowUnreachableCode, allowJs.
                              Поэтому можно сказать, что на Dart код получится «правильнее».
                              Нельзя. Парадигма другая, но это не делает ее априори «правильной».
                              • 0

                                Именно поэтому я взял слово "правильно" в кавычки. Имеется в виду, что на Dart получится более Javaподобный enterprise код чем на Typescript. Во Wrike захотели именно такого, но это не значит что это нужно всем.


                                Кроме того Dart это совершенно отдельный язык, такой же как и Kotlin, что может транслироваться в JS, а Typescript — это расширение JS.

                                • +1
                                  на Dart получится более Javaподобный enterprise код чем на Typescript

                                  А можно конкретный пример? Я не знаток Dart, но в списке возможностей на сайте не нашел ничего такого, чего нельзя было бы реализовать в Typescript (кроме, наверное, перегрузки операторов).

                                  Кроме того Dart это совершенно отдельный язык, ..., а Typescript — это расширение JS.

                                  Каким образом два этих факта говорят в пользу Dart?
                                  • 0

                                    Я слежу за большим проектом на Dart: https://github.com/sass/dart-sass
                                    Код там больше напоминает Java или C#, где в основном используются классы и ООП.


                                    На Typescript в таком стиле тоже можно писать. Но сам язык этого не требует, можно писать просто функции. Вот пример из исходников самого Typescript:
                                    https://github.com/Microsoft/TypeScript/blob/master/src/compiler/core.ts


                                    Поэтому те, кто хотят получить себе ООП в основе языка, а не в виде сахара поверх прототипов, выбирают Dart.
                                    bunopus ниже показывает то же самое на примере типов Car и Ford.

                                    • 0
                                      Но сам язык этого не требует
                                      Судя по исходникам указанного вами же проекта, Dart тоже не требует. Да и в целом, язык должен быть гибким и позволять организовать архитектуру как удобно, а жесткие ограничения — это задача фреймворков и корпоративного стайлгайда.
                            • 0

                              Ну если вкратце:
                              Типизация Dart более "строгая". Каноничный пример TS


                              interface Car {
                                  drive();
                              }
                              
                              interface Plane {
                                  drive();
                              }
                              
                              abstract class Ford {
                              
                              }
                              
                              class Focus extends Ford implements Car {
                                  drive() {
                                      console.log('I am driving');
                                  }
                              }
                              
                              let my_car: Focus = new Focus();
                              console.log(my_car instanceof Ford); // true
                              console.log(my_car instanceof Car); // Нельзя проверять интерфейсы в runtime!!!
                              

                              окей, пишем guard, но только на Plane


                              
                              function isPlane(arg: any): arg is Plane {
                                  return arg.drive !== undefined;
                              }
                              
                              console.log(isPlane(my_car)); // true, несмотря на то, что my_car другого интерфейса
                              

                              Да, можно сказать, что интерфейс это просто набор методов и свойств, так что всё правомерно, но это не так.
                              В Dart есть такая штука https://www.dartlang.org/guides/language/sound-dart


                              В Dart есть SDK. Туда входит то, для чего в TS и JS надо подключать сторонние библиотеки. Которые имеют свойство устаревать, конфликтовать и пр. Это напрример потоки (rx.js), зоны (zone.js) и многое другое

                              • 0
                                Вы пытаетесь скормить Typescript код, написанный для языков вроде Java / C# / C++, без учета местных идиом и особенностей. Неудивительно, что он работает не так, как вы ожидаете.

                                То, что в Typescript описывается ключевым словом interface, на самом деле является формой класса. Она действительно описывает только список методов и свойств и существует только на этапе компиляции. Поскольку типизация с Typescript структурная, классу не обязательно явно указывать интерфейс при объявлении, чтобы его реализовать — даже анонимный класс с необходимыми полями подойдет! С таким подходом можно писать более гибкие абстракции, не лишаясь строгой типизации — например, когда вы используете чужие классы и не можете внести в их объявление собственный интерфейс.

                                По поводу type guard: а почему вы решили, что на основании наличия метода drive можно сделать вывод о том, что объект принадлежит типу Plane? С точки зрения структурной типизации два интерфейса с одинаковыми сигнатурами являются одной и той же формой. Если нужно различать произвольные объекты, то можно использовать tagged union types.
                                • 0
                                  Вы пытаетесь скормить Typescript код, написанный для языков вроде Java / C# / C++, без учета местных идиом и особенностей. Неудивительно, что он работает не так, как вы ожидаете.

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


                                  Dart эту возможность предоставляет.

                                  • 0

                                    Я напомню, изначально я отвечал на вопрос


                                    Я прочитал параграф про «Почему не Typescript» два раза, но ответа на вопрос так и не нашел. Судя по всему, объективной причины нет и просто «так сложилось».

                                    Вот вам ответ: Dart мне позволяет писать в полностью ООП стиле. Именно в том, который в Java / C# / C++.
                                    Местные идиомы и особенности наверное хороши для тех, кто пришёл из JS и не имеет опыта в других языках, я же не осуждаю.

                                    • 0
                                      Вот мы наконец-то и докопались до истины. Более низкий порог вхождения с учетом существующего опыта команды — это весомый аргумент.

                                      С другой стороны, при работе с новым языком всегда приходится изучить определенный объем тонкостей — синтаксис, best practices, стандартная библиотека. На фоне этого объема различия между прототипным и классическим наследованием не выглядят такими уж существенными.
                                      • 0
                                        Тогда почему бы не использовать GWT(Если вы конечно работаете с Java)?
                                        • 0

                                          Вы уж извините, но от GWT уже пахнет :-) Он уже лет пять как устарел.

                                    • 0

                                      Да нет, каноничный вариант на TS будет выглядеть так:


                                      abstract class Car {
                                          readonly brand : string
                                          abstract drive() : void
                                      }
                                      
                                      abstract class Plane {
                                          readonly brand : string
                                          abstract drive() : void
                                      }
                                      
                                      class Focus extends Car {
                                          readonly brand = 'Ford'
                                          drive() {
                                              console.log( 'I am driving' )
                                          }
                                      }
                                      
                                      const my_car = new Focus
                                      console.log( my_car.brand === 'Ford' ) // true
                                      console.log( my_car instanceof Car ) // true

                                      Это например потоки (rx.js), зоны (zone.js)

                                      И зачем эти антипаттерны в стандартной библиотеке? :-)

                                    • 0

                                      Порождаемый Dart код может быть быстрее, чем js. Да, тут наверное самый скользкий плюс, так как он сильно разнится от примера к примеру. Но несомненный плюс в том, что в Dart действует парадигма из Java "Write once — Compile Everywhere". Т.е. когда я пишу код на Dart — я знаю, что с выходом новой версии v8 например, он будет скомпилирован в максимально эффективный js код. Например с выходом DDC (Dart dev Compiler) код компилируется в ES6.

                                      • 0
                                        Вкратце — потому что не от Google. Других причин нет, просто 1-2 людям, кто принимал решение и продвигал Dart, очень нравились (нравятся?) продукты от Google (SoyTemplates, Google Closure Compiler, Polymer, Angular, Dart)
                                        • 0

                                          Это не так, я уже выше расписал причины

                                      • 0

                                        Старые куски кода на js используете через package:js? Проблем с отложенной загрузкой не возникало?

                                        • 0

                                          Да, через него. Ну, каких-то особых не замечено, есть какие-то конкретные примеры?

                                          • 0

                                            Не нашел в дарте инструмента для подгрузки (deferred loading) js скриптов. Можно подгрузить классы-обертки над js кодом, но это не то, сам js скрипт не подгрузится таким способом.
                                            И получается все js скрипты надо гвоздями приколачивать или самому загрузчик писать

                                            • 0

                                              Да, к сожалению пока так :-(

                                        • –1
                                          Насчет выпиливания честно говоря немного удивлён. Сам сейчас пишу небольшой учебно-тестовый проект на dart (это просто новый мастер установки некоего моего ранее написанного продукта), до того писал на typescript. Резко не понравилось(по сравнению с typescript) то, что проект в тысячу строк порождает 300 килобайт компилированного кода на javascript (до минимизации). Сейчас с большим интересом смотрю в сторону scala.js. Очень жалею что не узнал об этой технологии раньше. И по-моему если уж говорить о чём-то заменяющем javascript, смотреть следует именно в эту сторону, а не на typescript, dart, kotlin и т.п. Дело в том, что возможно всё это и очень неплохие языки, но увы, все они нишевые. Нет, если разработчик желает постоянно оставаться в этой нише то пожалуйста. Но если он хочет быть более универсальным, то и изучать следует универсальный, пригодный почти для всего язык. Такой как scala.
                                          • –2

                                            Эм. Ну вы уж простите, но как по мне scala ещё более "нишевый" язык. И насчёт


                                            универсальный, пригодный почти для всего язык. Такой как scala.
                                            Звучит очень оптимистично
                                            https://trends.google.com/trends/explore?q=scala.js,%2Fm%2F0h52xr1
                                            • +1
                                              Ваша ссылка реально ни о чем. Ибо показывает не достоинство того или иного языка, а всего лишь его популярность. Ну а к утверждению что scala язык ещё более нишевой вообще не знаю как относиться. Что я могу владея scala:
                                              1) Писать для десктопа под JVM
                                              2) Писать для сервера (play 2, lift, etc)
                                              3) Писать клиентский код для броузера (scala.js)
                                              4) Заниматься data science (apache spark, tensorwlow, куча явовских библиотек)
                                              5) Заниматься хардварным дизайном https://chisel.eecs.berkeley.edu/ (на этом кстати написан новый опенсорсный процессор RISC-V)
                                              Единственно для чего scala непригодна, это для мобильной разработки(слишком толстый исполняемый код) и написания нативного кода. Да и то мобильная разработка станет вполне возможной в ветке scala-3, в которой обещают оптимизатор, а работа над нативным кодом идёт полным ходом (scala-native). Не покрытыми начиная с ветки 3 остаются пожалуй только две области. Это .NET и встроенные системы. Но к .NET возможно ещё вернутся. А для встроенных систем (работал с ними очень много) я даже С++ применяю с большой осторожностью и пишу фактически на С с классами. Ну и скажите на милость, что из всего этого умеет dart? Мне кажется беда scala — его репутация сложного языка. Причем совершенно не заслуженная. Его изначально боятся. Поэтому и Ваша ссылка показывает то что показывает.
                                              • +1

                                                А мы сейчас обсуждаем, что лучше Dart или scala? Я не знаю, так как на скале не писал. Из того, что вы перечислили Dart умеет всё, ну кроме маргинальных "data science и Заниматься хардварным дизайном"
                                                Инструмент должен уметь делать что-то хорошо, а не всё, иначе он превратится неизвестно во что.

                                                • 0
                                                  Да нет, что Вы! Избавь боже от обсуждений какой язык лучше, я давно уже вырос из того возраста когда это обсуждают. Я просто рассуждаю с сугубо потребительской точки зрения. Есть две технологии, А и B. Обе решают некую нужную мне здесь и сейчас задачу. Насколько хорошо и удобно они её решают, я пока не знаю, поскольку не владею ни А ни B. Однако мне известно, что область применимости B шире чем A. Спрашивается, какую из двух технологий я выберу для изучения и освоения? Наверно всё-таки B если она конечно не совсем уродская. Это единственное что я хотел сказать.
                                                  И кстати ни data sciense ни хардварный дизайн мне маргинальными не кажутся. Вторым я очень много в своё время занимался, правда на традиционном верилоге. Первым очень интересуюсь сейчас. На scala для продакшена пока ничего не писал. Сейчас этот язык у меня в стадии активного освоения. Следующий веб-проект хочу с нуля делать именно на scala.js. Кстати будет очень хороший повод сравнить scala и dart по удобству. Возможно даже напишу об этом на хабре.
                                                  • 0
                                                    Будем рады узнать о вашем опыте

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

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