Liscript — web REPL: поцелуи, велосипеды и экскаваторы

в 19:55, , рубрики: java, KISS, REPL, web, YAGNI, Программирование, Разработка веб-сайтов, функциональное программирование, холивар

Liscript — web REPL: поцелуи, велосипеды и экскаваторы - 1

Некоторое время назад я написал интерпретатор лиспоподобного языка, который назвал Liscript. Опубликовал несколько статей на Хабре, посвященных особенностям реализации ядра, TCO, GUI, REPL-ботов и т.п. Недавно добавил web-интерфейс REPL-у (ссылка в конце статьи).

При чем здесь поцелуи и экскаваторы? Думаю, большинству известны такие аббревиатуры, как KISS (keep it simple stupid — делай это проще, дурачок), YAGNI (You ain't gonna need it — Вам это не понадобится), а также высказывания людей разной степени великости про архитектурных астронавтов, «все должно быть сделано так просто, насколько возможно, но не проще», и т.п.

Допустим, перед вами стоит задача — выкопать яму. Какие есть варианты решения? Взять лопату и выкопать самому — дешево и сердито, но долго и возможно неоптимально (зависит от вашего уровня владения лопатой и размеров ямы). Отдать на аутсорс таджикам (не будем рассматривать здесь этот вариант, хотя я должен был его упомянуть). Взять экскаватор — быстро и эффективно, но затратно: бензин/аренда, плюс не факт, что он проедет в вашу садовую калитку, значит надо сносить/восстанавливать забор и т.д. Также, необходимо определиться с моделью (порой из 100500 вариантов), а если вы будете управлять им самостоятельно, надо разобраться во всех его рычагах и педалях.

Разумеется, если вы — профессиональный экскаваторщик, копаете по 200 ям за день, или вы стремитесь им стать, а изначальная задача (вырыть яму) нужна вам не сама по себе, а как тренировка или демонстрация ваших умений, тогда выбор очевиден (остается разве что вопрос модели). Но даже профессионал возьмет лопату, сажая цветы.

В общем, про выбор инструментов под задачи, и конкретные (подозреваю, что спорные) решения, которые я выбирал в процессе реализации проекта, под катом.

Реализация односвязного списка

В Liscript отсутствуют точечные пары (cons-ячейки), так что основная структура как кода так и данных в нем — список. В Java-версии интерпретатора я написал собственный простейший класс с полями car и cdr. Можно было взять стандартные коллекции Java типа LinkedList или ArrayList — скорее всего они лучше оптимизированы в плане аллокаций и дружбы со сборщиком мусора. Но я выбрал свой собственный велосипед, хотя это несложно отрефакторить ко второму варианту.

Токенизатор/Лексер/Парсер

Это пример поинтереснее. Нужно читать входной текст/строку и преобразовывать ее в готовое AST (абстрактное синтаксическое дерево), выделяя из текста токены и организуя их в иерархическую структуру. Задача более чем известная, существует целая обширная теория синтаксического анализа и разбора, и множество библиотечных реализаций различных парсеров, например www.antlr.org Но я принял решение написать свой простой велосипед на конечном автомате — у Лиспа очень простая грамматика и синтаксис, хотя конечно пришлось учитывать многострочные строковые литералы и комментарии. Более того — таких велосипедов у меня 3: в Haskell-реализации (несмотря на множество готовых решений: parsec, attoparsec и т.д.), в ядре Java-реализации и в GUI на Swing для синтаксической подсветки текста кода.

WEB backend

История болезни: это мой первый web-проект, в качестве хостинга приложения я выбрал Heroku, бесплатный тарифный план. Из систем сборки в одном Java-чате мне посоветовали Gradle, а не Maven, мотивируя различными привлекательными словами. Я поверил, выбрал на Heroku вариант Gradle-сборки, и демопример, скачавшийся мне на диск, использовал Ratpack (не знаю что использует пример Maven-сборки, не исключено, что то же самое). Поскольку опыта с другими web-серверами (да и web-технологиями вообще) у меня не было, надо было делать выбор — или не использовать этот демопример, а установить какой-нибудь Jetty, по которому имхо гораздо больше доступной информации в интернете, или использовать Ratpack, готовый и настроенный, но как-то разбираться с ним. Выбрал второй вариант, среди найденных примеров две трети было на Groovy, но в конечном итоге удалось разобраться как реализовывать долгие синхронные операции, а с рендерингом страниц все было просто.

WEB frontend

Здесь вообще просто море вариантов выбора самых различных технологий, ибо область бурно развивается уже много лет. И апологеты разных фреймворков доказывают всему миру (и друг другу), что их выбор лучше/эффективнее/перспективнее и только так надо «писать WEB в 2017 году» (С) Каждый из них по-своему прав, но какой выбор был у меня? Для решения сугубо утилитарной задачи — вырыть яму написать web-моринтерфейс своего REPL-а.

  • Использовать Java-фреймворки, умеющие генерировать вэб-интерфейс: Vaadin, FX и т.п. Тяжелые мощные экскаваторы, поддерживающие парадигму «написано однажды — копает везде».
  • Использовать многочисленные WEB-фреймворки/библиотеки, имя им легион: Angular, React,… Каждый со своим богатым внутренним миром блек-джеком функционалом и свистелками.
  • Написать все самому на голом ванильном Javascript / HTML / CSS.

Как вы наверное догадываетесь, я конечно же выбрал третий вариант :). Даже без использования jQuerry, потому что этот станок пришлось бы тоже изучать. Без Babel / Webpack и еще 100500 модных на фронте слов. Впервые в жизни ощутив радость отладки под различные браузеры, включая IE, я был вынужден захардкодить в CSS константы, вместо объявления их в начале файла, что само по себе убого, но IE у меня не хотел видеть эти объявления, а технологии генерирования CSS из других форматов, как предлагают различные модные фреймворки, подразумевали использование упомянутых фреймворков.

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

Сплит-панели

Мне для REPL-а они были очень нужны. Мощные фреймворки для вэб-GUI реализуют их в своем составе, но, исключив тяжелую технику, я рассмотрел более мелкие готовые реализации, и, попробовав 3-4, таки выбрал одну. Хотя она тянет за собой jQuerry, что мне не очень нравится (больше мне пока ни для чего он не нужен), но гораздо лучше реагирует в плане отзывчивости интерфейса. Если будет время/желание, может перепишу на свой велосипед, без jQuerry.

Подсветка кода

Здесь я считаю, что мне повезло — для решения этой задачи я сразу нашел великолепную библиотеку codemirror.net, разобрался в ее возможностях, написал плагин для синтаксиса своего языка и тему оформления. Не писал свои велосипедные парсеры/лексеры, потому что эта библиотека проста, легковесна и хорошо справляется со своей работой — как в статических текстовых областях, так и в динамике при редактировании текста кода пользователем.

Заключение

Разумеется, я в курсе, что вышеописанные принятые мной решения как минимум спорны и неоднозначны. Что можно (и с каких-то позиций даже лучше) было применить готовые технологические инструменты. Что я приобрел, написав свои парсеры / лексеры? Опыт в написании подобных велосипедов на конечных автоматах, полный контроль происходящего, возможность легкой кастомизации. Что потерял? Не разобрался с готовыми существующими парсерами, не освоил их, и если придется применять в будущем — я буду вынужден осваивать их с нуля. И такой же вердикт по каждому из приведенных вариантов отдельных локальных задач. Но в любом подобном случае надо делать выбор, поэтому приходится взвешивать все плюсы и минусы, и принимать последствия. А что по этому поводу думаете вы?

главная страница сайта Liscript — liscript.herokuapp.com
онлайн REPL — liscript.herokuapp.com/repl

Автор: Андрей

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js