[Из песочницы] Радость Haxe. Роман с обделенным вниманием языком программирования

Привет, Хабр! Представляю вашему вниманию перевод статьи The Joy of Haxe. FontStruct«s love affair with a neglected programming language.

Логотип Haxe в редакторе шрифтов FontStruct


Довольно грубая попытка воспроизвести логотип Haxe в редакторе шрифтов FontStruct

Недавно мы открыли исходный код наиболее важной части нашего модуля для создания шрифтов. Это библиотека fonthx для создания TrueType-шрифтов, и написана она на Haxe.
В данной статье практически нет кода. Если же вас интересует только код, то ознакомиться с ним можно на github, а его работа показана на примере простейшего редактора пиксельных шрифтов, построенного с использованием библиотеки fonthx.
Независимо от того, знакомы ли вы с Haxe или нет, проект fonthx возможно заинтересует вас, так как в нем демонстрируются некоторые удивительные возможности языка, малоизвестные вне сообщества Haxe — в частности, возможность писать код на одном приятном языке с дальнейшей компиляцией / трансляцией не только в Javascript, но и во множество других платформ, в случае fonthx такими платформами являются JVM (код проекта транслируется в Java), нативный код (C++ или C #), NodeJS или WASM.

Меня можно назвать убежденным полиглотом. Как и многие другие разработчики, я пишу код на разных языках и, уважая серьезные намерения тех, кто предпочитает специализироваться только на каком-либо одном языке, я также опасаюсь всех тех фанатов и мошенников-евангелистов, которые твердят об одном истинно верном языке. Но что же побудило меня использовать такой нишевый язык как Haxe для создания ключевых компонентов FontStruct, а также написать данную статью? И что же такое Haxe?

Haxe


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

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

Большинство разработчиков знакомы с понятием «изоморфной» разработки, когда программист пишет и серверный и клиентский код на одном языке. Чаще всего в качестве такого языка используется Javascript или TypeScript, но также может использоваться любой другой язык, способный компилироваться в Javascript. Haxe в данном направлении идет намного дальше, открывая ряд интересных дополнительных возможностей. Из одной кодовой базы на Haxe возможно скомпилировать исполняемый файл, Java-приложение, WASM-модуль, приложение на NodeJS, приложение, работающее в браузере, мобильное приложение, и даже библиотеки для таких языков как PHP, Lua или Python.

В FontStruct мы пользуемся данной возможностью, разрабатывая ключевые компоненты нашего приложения на Haxe. Серверные модули компилируются как Java-сервлеты, а модули клиента скомпилированы в виде приложений на JS. И хотя в настоящее время мы фокусируемся в основном на этих двух целевых платформах (а также на NodeJS для запуска тестов на скорость), мы также рассматриваем возможность использования инструментов, предоставляемых экосистемой Haxe, для создания мобильных приложений на C++. Кроме того, использование Haxe в дальнейшем может позволить создать нативное (не основанное на Electron) настольное приложение.

Благодаря тому, что Haxe поддерживает такое множество целевых платформ, он лучше всех (по крайней мере для наших задач) реализует идею «напиши код один раз — запускай его везде», лучше чем любой инструмент, с которым я встречался за последние двадцать лет. Это дает ощущение того, что один и тот же код возможно скомпилировать под любую платформу или среду выполнения.

Процесс принятия Haxe


FontStructor - бесплатный редактор шрифтов на FontStruct.com
FontStructor — бесплатный редактор шрифтов на FontStruct.com

Более 10 лет назад, когда FontStruct был запущен, для редактора шрифтов FontStructor, а также для виджетов для просмотра шрифтов использовался Adobe Flash. А для создания TrueType-шрифтов на сервере использовался совершенно независимый код, написанный на Java.

Старая Flash-версия редактора FontStructor
Старая Flash-версия редактора FontStructor. Все элементы управления в нем рисовались во Flash. Обратите внимание на странные полосы прокрутки на панелях слева. Со временем главное меню в верхней части страницы постепенно расходилось визуально и функционально с html-меню, используемом в остальных частях сайта. Здесь нет ни DOM, ни CSS

Хотя FontStruct был и остается огромным успехом, наши первоначальные технические решения не прошли проверку временем. Развитие веб-стандартов и отсутствие поддержки плагина на мобильных платформах сделали Flash непригодным для использования в веб-приложениях. Также нам приходилось иметь дело с дублированием кода между сервером на Java и клиентом на Flash, а также между Flash и остальными частями клиента, написанными на HTML/JS/CSS. Было необходимо постоянно синхронизировать между собой три кодовые базы как с точки зрения функциональности, так и дизайна.

В 2013 году мы начали рассматривать возможность использования Haxe, в частности, в качестве средства для перевода редактора FontStructor с Flash на HTML5. В наших первоначальных исследованиях мы обнаружили, что уже имеются доступные инструменты для автоматического преобразования ActionScript кода в Haxe (as3hx) и даже Haxe-порт MVC-фреймворка Robotlegs, который мы использовали во Flash-версии. И так мы начали эксперимент по портированию клиента.

Медленный и полный проблем старт


Наш первый год отношений с Haxe сопровождался нерешительностью и сомнениями.

По нескольким причинам, и не в последнюю очередь из-за ограниченности ресурсов, которые мы могли бы ему посвятить, процесс портирования оказался довольно медленным. Как уже отмечали другие авторы, инструмент для автоматического преобразования ActionScript-кода в Haxe (as3hx) оказался очень полезным, но не лишенным недостатков — полученный с помощью него код пришлось дополнительно просматривать и править. Во время этого процесса пришло понимание того, что наша кодовая база раздута и ошибочна в своем дизайне, поэтому параллельно с портированием мы решили внести улучшения, тем самым еще больше замедлив дальнейший прогресс. Кроме того, Haxe был для нас новым языком, поэтому мы неизбежно делали ошибки, изучая этот язык и его инструменты.

Безусловно, самой большой нашей ошибкой было решение дополнительно использовать сторонний UI-фреймворк на Haxe.

Для Haxe существует множество таких фреймворков (возможно, их даже слишком много), предоставляющих унифицированный API-интерфейс для отрисовки графики на различных платформах. OpenFL и NME являются примерами таких фреймворков и предоставляют инструменты для сборки приложений на Haxe под мобильные платформы и даже консоли. При этом они предоставляют реализацию Flash API для отрисовки графики. Все это казалось очень заманчивым — мы могли перенести наше приложение на HTML5, используя знакомое API и, возможно, даже создать одновременно с этим приложения для Android и iOS!

Поэтому для портирования нашего приложения на Haxe мы решили использовать еще и OpenFL.

Я не хочу проявить неуважение к OpenFL (мне даже хочется сказать, что: «Проблема не в OpenFL, а в нас»). OpenFL — фантастический проект, который хорошо показал себя во многих проектах, и мы можем вернуться к нему в будущем, но после портирования порядка 90% нашего приложения на Haxe, мы решили все же отказаться от него.

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

Самым главным для нас стало то, что сгенерированный с помощью OpenFL HTML5-код идеален для игр, но для такого приложения как FontStruct он не подходит. Все, чего мы хотели в итоге, это отобразить в браузере обычное DOM-дерево, которое мы могли бы стилизовать с помощью CSS, а не набор canvas-элементов или спрайтов, созданных OpenFL.

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

Веселье


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

И работать с Haxe — это весело. Он, можно сказать, создан специалистами по веселью — независимыми разработчиками игр. Разработчикам игр нужна быстрая компиляция, а также единая кодовая база для создания приложений для настольных компьютеров, браузеров, iOS, Android и консолей. Разработчикам игр нужен производительный и стабильный код. И Haxe предоставляет все эти замечательные возможности, и не только для разработчиков игр.

Не побоюсь высказать идею о том, что одна из самых больших проблем Haxe — относительно небольшой размер его сообщества и связанная с этим разреженность его экосистемы — также является его преимуществом с точки зрения опыта для разработчика. Работая с Haxe, вы вряд ли будете тратить часы на гугление и поиск информации на stack-overflow, или на разбор и сравнение разных уроков по интересующей теме, а также во время изучения API какого-нибудь нового фреймворка или библиотеки — этих ответов, уроков и библиотек вполне может просто не быть. А если и есть, то, скорее всего, они будут единственными материалами по данным темам. С Haxe вы будете решать задачи программирования самостоятельно (!), самостоятельно писать библиотеки или, не испытывая ни малейшего чувства вины, даже самостоятельно заново изобретать или портировать колесо. Это весело и дает свободу, и это то, к чему многие разработчики стремятся после бесконечных фреймворков и современной разработки, связанной с копированием кода из разных источников. Используя принцип «меньше — значит лучше», Haxe не уникален, но это его определенный плюс.

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

Рендерер FontStruct


Запуск нашего первого компонента на Haxe для сайта FontStruct в апреле 2015 года был странным и неожиданным событием.

Галерея является центральной частью FontStruct: доступные для поиска, сортируемые списки тысяч шрифтов, созданных на нашей платформе. С самого начала в 2008 году у нас были постоянные проблемы со скоростью загрузки и с производительностью предварительного просмотра шрифтов как в самой галерее, так и на других страницах сайта.

Предварительный просмотр шрифтов в галерее FontStruct
Часть страницы галереи FontStruct, где показан предварительный просмотр шрифтов, созданных на платформе. Первоначально каждый отдельный элемент предварительного просмотра был представлен медленно загружаемым Flash-роликом!

Поскольку шрифты FontStruct («FontStructions») хранятся в проприетарном формате и часто редактируются, невозможно использовать их для рендеринга, как обычные TrueType-шрифты. Это означало невозможность создания на сервере растровых изображений для предварительного просмотра шрифтов (с использованием библиотеки FreeType).

Чтобы «решить» эту проблему, в самые ранние дни жизни FontStruct мы использовали отдельные Flash-ролики для элементов галереи. Каждый Flash-ролик загружал и парсил данные в нашем проприетарном формате, и затем показывал на клиенте изображение для предварительного просмотра. При отображении на странице 20 и более таких роликов, каждый из которых загружал данные и пытался отрисовать шрифт, время загрузки и потребление ресурсов пользовательской машины значительно увеличивались, и ситуация еще больше усугублялась со временем, так как шрифты, разработанные в нашем редакторе, становились все более и более сложными.

В конце концов мы использовали причудливое гибридное решение: при самом первом просмотре шрифта использовался Flash-ролик, который генерировал изображение для предпросмотра, затем данное изображение захватывалось и сохранялось на сервере в виде PNG-файлов. И для предпросмотра для следующих пользователей уже использовались сохраненные на сервере PNG. — Этот странный хак значительно улучшил время загрузки страницы, но он был грязным и, в конечном счете, неправильным что ли. Верным решением было бы написать совершенно новый серверный модуль — например, на Java или PHP — для загрузки и парсинга данных шрифта, и дальнейшего создания на его основе растрового изображения, но у нас просто не было ресурсов для этого.

Тем временем процесс портирования Fontstructor на Haxe продвигался очень медленно, и мы были далеки от релиза. Но мы продвинулись достаточно далеко, чтобы понять, что новый код на Haxe может решить наши проблемы с предварительным просмотром шрифтов в галерее.

У нас уже был Haxe код для загрузки и парсинга нашего формата шрифтов. У нас был код для отрисовки глифов (на Canvas в HTML5 или на спрайтах во Flash). У нас также были все компоненты, необходимые для решения проблемы на стороне клиента. Могли ли мы адаптировать этот код для использования на сервере?

Да! После того, как мы осознали это, процесс пошел очень быстро. Сначала мы думали задействовать C++ и библиотеку Cairo для отрисовки шрифтов (надеясь, что мы сможем написать расширение для PHP или какой-нибудь CGI-модуль), однако вместо этого было решено использовать Java. — Как замечательно иметь возможность сделать такой фундаментальный выбор с помощью нескольких строк кода и условной компиляции! Мы также могли использовать для этого NodeJS и node-canvas, но мы уже были знакомы с процессом создания и развертывания Java-сервлетов, и в Java есть все необходимые нам функции для отрисовки и манипулирования растровыми изображениями. Возможно, писать код на Java нам было не по нраву, но с Haxe такая необходимость отпадает.

Код для отрисовки
Такой высокоуровневый код для отрисовки может быть скомпилирован и запущен как на клиенте (JavaScript), так и для сервере (в JVM)

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

Прощание с Flash (и c ванильной Java)


В ноябре 2015 года, то есть спустя 7 месяцев, мы успешно запустили первый клиентский модуль на Haxe — HTML5-версию виджета для предпросмотра шрифтов. Я думаю, что наши пользователи практически не заметили изменений, что с одной стороны как-то разочаровывает, но, в конечном счете, является показателем успешности данного начинания.

Теперь у нас оставался только один Flash-модуль на сайте — редактор FontStructor, и нам понадобился еще один год, чтобы, наконец, запустить в ноябре 2016 года его HTML5-версию. Так настало время окончательно отказаться от нашего AS3-кода и объявить FontStruct свободным от Flash.

Новая HTML5-версия FontStructor
Новая HTML5-версия FontStructor, запущенная в 2016 году

В августе 2018 мы портировали на Haxe модуль генерации шрифтов «FontMortar». Этот последний порт позволил нам полностью отказаться от кода, написанного на Java.

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

Погружаясь глубже в Хакс


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

  • Поддержка языка со стороны IDE вполне приличная и постоянно улучшается, активно развиваются модули под IntelliJ Idea и Visual Studio Code.
  • Haxe предоставляет средства для работы с нативным кодом и библиотеками, таким образом, он не ограничивает ваши возможности, навязывая лишь небольшое подмножество доступных функций. Если вы ведете разработку под JavaScript, то у вас есть возможность использовать любую JavaScript-библиотеку, например, для работы с React доступны различные биндинги. Для FontStructor мы используем несколько npm-модулей, таких как interactive.js и opentip. Написание биндингов для них заняло всего пару минут.
  • Haxe имеет надежную продвинутую систему типов с такими возможностями как параметризация типов, обобщенные классы и методы, абстрактные типы и выведение типов.
  • В Haxe есть чрезвычайно мощные макросы, обеспечивающее доступ к AST во время компиляции, что позволяет разработчикам добавлять свои собственные языковые конструкции и генерировать код динамически.
  • Несмотря на то, что по Haxe в интернете не так уж и много ресурсов, для него есть репозиторий библиотек, покрывающих общие потребности разработчиков за пределами стандартной библиотеки (кроме того на Github можно найти еще больше репозиториев, не представленных на haxelib — прим. переводчика).
  • И последнее, но от этого не менее важное: у Haxe очень талантливое и отзывчивое сообщество.


Заключение


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

Звучит здорово, но у него такое маленькое сообщество. Что с ним будет через 5 лет? Сайт вроде нормальный, но почему-то он не выглядит современным. И это не внушает доверия.
Кажется, что он не так уж хорошо документирован.

Разве это не для инди-разработчиков игр?

Спустя пять лет использования Haxe, я искренне удивлен тем, что не сожалею о нашем выборе данной технологии. Несмотря на все недостатки и все сложности, вызванные ими, несмотря на относительно небольшое сообщество и отсутствие крупных корпоративных спонсоров, Haxe полностью справляется со своими задачами. С Haxe я чувствую свободу и независимость от какой-либо платформы. Теперь у нас единая кодовая база для основных компонентов FontStruct, в то время как раньше их было две. За прошедшие несколько месяцев работы новые версии сервлетов, отвечающих за генерацию шрифтов и изображений для предварительного просмотра, ни разу не давали сбоев. Новые HTML5-редактор и виджет для предварительного просмотра теперь работают во всех браузерах, включая мобильные, тогда как раньше мы были вынуждены работать с устаревшей и умирающей технологией.

И, если отбросить практическую выгоду, работа с Haxe приносит радость и чувство волшебства, радость Haxe!

© Habrahabr.ru