Около трех лет назад ко мне обратились Джорджио Серра и Дэвид Стоун, два основателя Exit Live, онлайн-платформы, которая позволяет артистам продавать свои концертные записи фанатам. Проект был не более чем идеей, хотя и очень яркой. Они нашли меня через мои проекты с открытым исходным кодом, в частности Dropzone, и подумали, что мои навыки отлично подойдут для компании, поэтому они предложили мне ни к чему не обязывающее приглашение прийти и разработать основу, на которой Exit Live должен строиться технологично. Я уверен, что они знали, что их энтузиазм по поводу проекта был заразительным, и что в конечном итоге я стану основным членом команды в качестве ведущего разработчика и технического директора.

В то время я в основном программировал на JavaScript; как на бэкэнде с Node.js, так и во фронтенде с различными более крупными фреймворками (такими как Ember.js или AngularJS) или меньшими библиотеками и инструментами, и я усвоил одну вещь: никогда не начинать большой проект снова с JavaScript.

В JavaScript есть что полюбить: он вездесущ, прост в освоении, хорошо поддерживается практически всеми редакторами и IDE, имеет огромную базу пользователей и библиотеки для всего, что вы можете придумать. Но в этом есть и много вещей, которые можно не любить, и я с самого начала знал, что не хочу попадать в ту же ловушку, что и раньше: быстрая начальная разработка за счет запутанного кода, который трудно поддерживать.

Мы рассмотрели следующие серверные языки:

  • Старая школа и проверенная в боях Java (например, Spring)
  • RubyRuby on Rails в качестве основного кандидата)
  • Go (твердый язык, но немного диковинный)
  • Дротик (новичок в блоке, без ярких примеров)

Языками клиента были:

  • JavaScript (единственный родной язык в браузере)
  • TypeScript (расширенный набор Microsoft JavaScript)
  • Дротик

CoffeeScript на самом деле не рассматривался, потому что я возненавидел его (после того, как написал в нем много строк кода).

Почему мы выбрали Дарт

В то время я предпочитал Дарт. Я не только лично участвовал и был привязан к языку (мой брат Флориан Лойч работал над компилятором в то время и с тех пор был назначен менеджером библиотеки), но, похоже, у него было много чего:

  • Он был типизирован, но не таким тяжелым, как Java, поскольку в нем была представлена ​​довольно новая концепция необязательных типов. Одно это решило многие проблемы, которые у меня были с JavaScript.
  • У него была собственная среда выполнения, а это значит, что мы могли использовать его прямо на сервере (а не компилировать в JavaScript, работающий на node.js).
  • Он поставляется с множеством отличных основных библиотек, что делает его очень удобным для работы с DOM без использования сторонних библиотек.
  • У него был собственный менеджер пакетов (в отличие от JavaScript, где вам нужно выбрать один из множества менеджеров пакетов).
  • У него было самоуверенное руководство по стилю, которому мы могли следовать, вместо того, чтобы определять и писать свои собственные руководства.
  • Это был единственный язык, который имел возможность сделать его родным языком браузера с собственной виртуальной машиной (что, к сожалению, так и не стало реальностью).
  • Потенциально он был быстрее, чем JavaScript и Ruby, поскольку разработчики, создавшие этот язык, пришли из движка JavaScript V8 и разработали язык, чтобы он был более оптимизируемым.
  • Он хорошо знаком разработчикам на Java и / или JavaScript, и их легко освоить.

Все это указывало на то, что Дарт - отличный кандидат! У нас будет один и тот же серверный и клиентский язык - язык, на котором я бы с удовольствием писал (в отличие от Java или JavaScript), с которым я был знаком (в отличие от Go) и на котором было бы легко найти новых разработчиков. благодаря его знакомству с JavaScript и Java.

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

Мы обсудили все эти плюсы и минусы и наконец пришли к выводу: давайте рискнем и создадим что-то с помощью инструментов, которые нам нравятся, а не инструментов, которые безопасны.

Это был смелый шаг, но Exit Live - это смелость.

Наш первый год с языком, которого никто не знал

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

Программный аспект

В то время лучшим способом работы с Dart была специальная, но уже не поддерживаемая IDE DartEditor, которая представляла собой настраиваемую сборку Eclipse. Хотя до этого мне никогда не нравилось работать с Eclipse, они отлично справились со всем ненужным беспорядком и оптимизировали работу с Dart. Работая с своим редактором и используя свои рабочие процессы, мы убедились, что все в команде получили полный «опыт работы с Dart»: завершение кода, предложение типа, переход к определению и т. Д. Я думаю, что это сэкономило нам много времени на этапе настройки, потому что нам не нужно было начинать настраивать инструменты и писать инструкции, что особенно сложно с новым языком.

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

Выбор нашей серверной инфраструктуры

Прежде чем я начал работать в Exit Live, я работал над очень амбициозной торговой платформой. Как было современно в то время, мы построили всю нашу инфраструктуру на микросервисах. У нас был файловый сервер, средство визуализации шаблонов, бэкэнд, средство визуализации внешнего интерфейса и т. Д. Все экземпляры Node.js или Java обменивались данными друг с другом через JSON API. Хотя концепция хороша, развертывание и отладка было кошмаром, особенно с учетом того, что мы запускали собственные серверы с нашими собственными инструментами масштабирования.

Я не «серверный парень» и мне не нравится возиться с конфигурациями серверов, поэтому с Exit Live я хотел пойти полностью противоположным путем: использовать решение Google App Engine - полностью размещенную, автоматически масштабируемую серверную инфраструктуру с балансировкой нагрузки и работоспособностью. чеки.

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

К сожалению, в то же время в 2014 году Google работал над полным пересмотром своих сервисов App Engine и Compute Engine с намерением ввести гибрид: управляемую серверную среду с автомасштабированием (например, App Engine), но с полным контролем и гибкостью что работает на этих серверах (например, Compute Engine), который теперь известен как Google Flexible Environment.

Это привело к тому, что команда App Engine не захотела добавлять Dart в качестве поддерживаемого языка, аргументируя это тем, что скоро можно будет запускать серверы Dart в новой гибкой среде. Для этих изменений не было конкретных сроков, поэтому нам приходилось надеяться, ждать и смотреть.

Поскольку наш проект был довольно амбициозным и одним из крупнейших, написанных на Dart, мы получили приглашение сделать презентацию на Google I / O 2014 - по иронии судьбы в том же самом Google I / O, где они анонсировали свои новые решения Google App Engine. Итак, мы были здесь, настраивая нашу инфраструктуру на взломанных вместе серверах, чтобы иметь возможность представить нашу работу на той же конференции, где была представлена ​​и выпущена важная и отсутствующая часть нашей платформы.

В итоге мы продемонстрировали написанную нами библиотеку RPC, которая обеспечивала прозрачную связь между нашим сервером и клиентом, с классами, которые можно было использовать с обеих сторон. Поскольку в Dart есть типы, вы должны создать свое сообщение на клиенте с полным автозаполнением, отправить его на сервер и знать, чего ожидать на сервере, вместо отправки произвольных данных JSON. Это был прекрасный пример для демонстрации сильных сторон Дарта.

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

Выбор нашей клиентской базы

Чем больше мы продвигались, тем важнее становилось найти хорошую клиентскую среду, на которой мы могли бы строить. В Dart есть отличные библиотеки для управления встроенной моделью DOM, но для создания приложения размером с Exit Live требуется прочная структура, на которой будет построена правильная маршрутизация, внедрение зависимостей и т. Д.

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

Однако полимер не является каркасом приложения. В нем отсутствует маршрутизация или внедрение зависимостей, это просто очень элегантный способ инкапсуляции и повторного использования элементов на веб-сайте; что было достаточно для нас в то время.

Но работать с Полимером было неприятно. Версия Dart была просто оболочкой для библиотеки JavaScript, находящейся под ней, поэтому ежедневно приходилось отлаживать множество странных ошибок и ошибок.

Позже было объявлено, что Angular будет поддерживать нативную версию Dart, и как только она была выпущена, мы начали переносить клиент на angular. Около 6 месяцев мы запускали Angular и Polymer одновременно, пока полностью не избавились от Polymer.

Все остальные

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

Мы решили использовать Google Datastore - решение, которое казалось логичным, учитывая, что мы хотели использовать всю серверную инфраструктуру Google и что мы приняли решение согласиться с тем, что мы будем заблокированы в их службах, чтобы позволяют более быстрое развитие. Была только одна проблема ... не было библиотеки Dart для связи с Datastore! Поэтому нам пришлось начать реализацию собственной библиотеки (и, конечно же, позже, обменять ее с официальной библиотекой, опубликованной самим Google).

У нас есть альфа-версия Google Flexible Environment (которая в то время называлась «Виртуальные машины, управляемые Google App Engine»), поэтому мы могли начать разработку с ее помощью, но развертывание или запуск приложения Dart на ней оказалось намного сложнее. чем мы надеялись. Мы регулярно сталкивались с проблемой «Слишком много файлов», потому что процесс развертывания пытался рекурсивно копировать все зависимости из-за того, как программы Dart были структурированы в то время. В общем, цикл обновления для проверки изменений стал очень медленным. Но постепенно он становился все лучше и лучше, и команда Dart проделала большую работу по решению всех проблем, с которыми мы столкнулись.

Это был дикий запад… библиотеки появлялись и исчезали. Люди создавали проекты и отказывались от них. Трудно было решить, какие использовать. Это никогда не бывает легко, и риск смерти проекта с открытым исходным кодом существует для каждого языка, но он был усилен из-за того, что Dart был таким новым языком.

Собираем все вместе - хорошие стороны

В конце концов, у нас все заработало. Мы работаем в гибкой среде Google с непрерывной доставкой, прочной кодовой базой и отличной средой разработки.

Теперь мы пожинаем плоды выбора Дарта, и весь хаос и препятствия, с которыми мы столкнулись, остались в далеком воспоминании - забавные истории, которые мы вспоминаем время от времени и не можем поверить, что пережили.

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

Форматирование и руководство по стилю dart

Две, казалось бы, второстепенные утилиты в процессе разработки Dart оказались огромной экономией времени: превосходный Dart Formatter (написанный Бобом Нистромом) и Подробное руководство по стилю Dart. Я потратил часы (возможно, дни) на обсуждение вопросов форматирования в мерж-реквестах. Что следует использовать - табуляции или пробелы? Лучше добавить новую строку после if (condition) или фигурная скобка должна быть на той же строке? У меня есть свои предпочтения по всем этим вопросам, но на самом деле я просто хочу, чтобы они были единообразными! Я хочу, чтобы решение было принято, и в идеале я не являюсь его авторитетом, потому что я буду пересматривать свои решения и начинать рефакторинг своего кода каждые несколько месяцев.

Мы настроили наши тесты таким образом, что первый запускаемый нами тест проверяет, соответствует ли наша кодовая база Dart Formatter. Это означает, что в запросе на слияние невозможно ввести код, который не идеально отформатирован. Больше никаких дискуссий; больше нет ”You forgot a space here” комментариев к обзору.

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

Дерево трясется

Одна из самых недооцененных функций Dart - это его тряска дерева при компиляции клиентского кода.

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

В мире JavaScript это очень распространенная проблема. Библиотеки гордятся тем, что они настолько малы, насколько это возможно - на самом деле, это один из первых показателей, который вы часто видите на их веб-сайтах.

Возможно, вы захотите использовать Moment.js, но действительно ли стоит 16 КБ только для отображения даты? Некоторые функции jQuery хороши, но хотите ли вы получить весь ненужный багаж? Эта проблема является корнем многих менеджеров пакетов JavaScript, которые пытаются решить ее, разделяя библиотеки на минимально возможные части, чтобы избежать отправки ненужного кода.

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

Рефакторинг

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

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

Основные библиотеки и инструменты

Вам когда-нибудь приходилось решать, какую библиотеку Promise / Future использовать в JavaScript? Какой менеджер пакетов вы используете? Вы когда-нибудь слышали о Grunt, Gulp, Webpack, Bower и т. Д. Вы не можете игнорировать их, потому что из коробки сам по себе JavaScript ужасен, но выбор бесконечен, и каждый год появляется новый блестящий горячий инструмент, который все прыгают на борту с.

Я был частью этой толпы, и мне хорошо известно, какое волнение у меня возникло, когда было объявлено о новой библиотеке или инструменте JavaScript, которые, наконец, упростят что-то или решат другую проблему.

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

Вы хотите установить пакеты? Воспользуйтесь Пабом. Хотите автоматизировать рабочие процессы? Воспользуйтесь Шлифовщиком. Хотите использовать библиотеку Future / Promise? Используйте собственные библиотеки Dart и async/await ключевые слова. Хотите хороших функций манипулирования DOM? Дарт тебя прикрывает. Форматирование кода, отладка, анализ, тестирование и имитация фреймворков? Ага. Все там. И не из 10 решений на выбор, а в большинстве случаев стандартное.

Итак, все ли эти библиотеки и утилиты совершенны? Нет. Но они хорошие и становятся лучше, и многие из них почти идеальны.

Я бы снова выбрал Дарт?

Я сейчас невероятно доволен тем, как построен наш проект. Мне до сих пор нравится использовать Dart в качестве основного языка программирования, и с каждым годом он становится лучше. Наш код стабилен, быстро отлаживается, хорошо подходит для совместной работы, его легко читать и понимать. Поэтому мне очень приятно, что мы решили использовать Dart три года назад. Без сомнения, я бы использовал его снова для своего следующего проекта.

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