Как мы сделали из JSON язык программирования

Original author: Adolfo Rodriguez
  • Translation
Спустя месяцы напряжённой работы мы наконец выпустили приложение для iOS Relevant. С ним мы ломаем существующие устои взаимодействия с сервисами и контентом в сети, благодаря чему пользователь тратит куда меньше времени на привычные вещи. Достигается это путём представления приложений и веб-сервисов в виде карточек (подробнее здесь).

Карточки, как независимые интерактивные единицы, показывают, каким будет будущее мобильных интерфейсов.
image
Когда мы только начали работать над Relevant, нам были ясны лишь две вещи: карточки должны быть красивыми, и они должны быть универсальными. То есть их содержание может формироваться из любого источника информации в сети с минимальными ограничениями. Что до красивости, так она заслуживает отдельной статьи, и здесь мы её касаться не будем, а поговорим именно об универсальности.

Карточки как объекты JSON


Так как карточки Relevant должны быть лёгкими и скачиваемыми, мы решили представлять их в виде JSON-файлов, содержащих инструкции о том, как получить доступ к различным источникам информации и API в сети и как преобразовать полученные данные в содержимое карточек.
image
Требовалась необычайно гибкая структура карточек, которая бы не усложняла процесс их создания. Должна быть возможность, например, получения от API массива с товарами, а затем и получение подробной информации о каждом из них. Причём получение данных может происходить посредством разных API с последующим сбором всего этого воедино.

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

API нестандартны


Веб-сервисы и API представлены в виде самых разных форм. Некоторые API, когда требуется вернуть список, возвращают просто массив, в то время как другие засовывают его куда-то в недра возвращаемого объекта. Одни используют разбиение на страницы, другие принимают явный параметр страницы. [Не совсем ясно, в чем заключается подразумевающаяся разница] Добавьте к этому сотни стандартов формата даты и времени, пару стандартов URL и случайное оборачивание целых и дробных чисел в кавычки. Большинство разработчиков, пытающихся создать систему агрегации многочисленных API, быстро погружаются в многоуровневый ад из блоков if-else.

Нам хотелось чего-то более мощного. Требовалось сделать нашу платформу независимой от качества дизайна API и его данных. После долгих проб и ошибок Relevant Card’s JSON стал выглядеть примерно так:
image

Большая часть нашей инфраструктуры агрегации API лежит на сложных серверных и клиентских системах. Тем не менее, придуманный нами JSON-ориентированный язык REL заслуживает отдельного упоминания.

Быстрое введение в REL


REL выглядит как приукрашенный JSON, но по сути это чисто функциональный язык программирования с ленивыми неизменяемыми переменными (то есть они вычисляются и получаются только тогда, когда необходимы) и динамической областью видимости.

Типы и переменные


Типы в REL — это стандартные типы JSON: числа, строки, объекты и массивы. В большинстве случаев они парсятся непосредственно. Однако некоторые объекты имеют особое значение. Пары ключ-значение объекта, имеющего ключ "_RETURN", парсятся как пары переменная-значение. Обращение к переменным осуществляется посредством фигурных скобок: "{variable_name}".

Например, следующий объект
{
    "foo":1,
    "var":2,
    "_RETURN":{"_MATH":"{foo}+{var}"}
}
REL представляет как число 3.

Функции


Мы часто добавляем новые встроенные функции в REL. Эти функции выглядят как объекты с определёнными специальными ключами, которые начинаются с символа подчёркивания. Функция "_MATH" из примера выше разбирает строку как математическое выражение и возвращает его результат.

Среди других встроенных функций можно выделить "_URL", которая загружает JSON по заданному адресу, и "_PATH", которая ищет значение в объекте JSON или массиве. Эти две функции являются основными, использующимися для агрегации API в REL Engine.

Можно даже создавать пользовательские функции. Больше информации об этом в документации.

Управление порядком выполнения


Встроенные функции, такие как {"_IF":, "_THEN":, "_ELSE":} и {"_LOOP": {"_ARRAY":, "_EACH":}} используются для управления порядком выполнения, но, в отличие от нефункциональных языков (таких как C или Java), они всегда возвращают значение.

Больше информации о текущей версии REL всегда можно найти в документации.

Также доступна развивающаяся библиотека карточек с примерами и описаниями на REL.

От переводчика


Перевод местами достаточно вольный, но не в ущерб смыслу или содержанию. Все, что не относится напрямую к оригиналу, вынесено в примечания. Автор публикации является по совместительству и автором приложения, так что исходный текст является несколько рекламным. Я постарался перенести акцент именно на разработанный язык. За большим количеством ссылок и разнообразных призывов обращайтесь к оригиналу.
С предложениями, пожеланиями и замечаниями, как обычно, в ЛС.
Ads
AdBlock has stolen the banner, but banners are not teeth — they will be back

More

Comments 31

    +3
    Какой-нибудь диалект Lisp смотрелся бы лучше.
      +28
      Тут бы любой нормальный язык прогрммирования смотрелся бы лучше
        –2
        Задача сводилась к тому чтобы сделать именно из декларативного формата.
          +16
          Только получился почему-то императивный язык, который прилично так изуродовали
            0
            Не вижу противоречия. Взяли декларативный формат и разработали правила для описания императивной программы. «Уродство» – следствие имеющихся ограничений формата.
              +2
              На выходе нужен был JSON. Видимо, поэтому авторы и подумали, почему бы не сделать его и на входе. Требовалось расширить имеющийся инструмент. Объектом вдохновения могли быть, например, препроцессоры CSS: человек, знакомый с CSS, разберется с препроцессором в мгновение ока. Но одно дело — развить формат описания данных в расширенный формат описания данных или расширить язык программирования до языка программирования с большими возможностями. И совсем другое — расширить формат описания данных до языка программирования.

              В простейших случаях, возможно, доля удобства в этом и будет, но только в них. Конструкции получаются громоздкими, а решения проблем, обозначенных как предпосылки к созданию нового языка, я не увидел.
                0
                Точно. IoC в HATEOAS/JSON-API гораздо интереснее в плане сохранения декларативности json, и одновременно передачи api управления поведения приложения.
                0
                Ну, например, если из приведённого JSON (литералов JavaScript) удалить двоеточия, получится валидный edn (литералы Clojure), чем не декларативный формат. На этом этапе разницы практически никакой, но зато можно весь этот "_WTF" заменить на обычные вызовы функций и получить вполне пристойный EDSL. Да, в сущности, и на JavaScript можно было бы, но авторы же хотели иммутабельность и ленивость из коробки?
                0
                «Любая достаточно сложная программа на C или Фортране содержит заново написанную, неспецифицированную, глючную и медленную реализацию половины языка Common Lisp» © Филип Гринспен
                +11
                Противоречие тут в другом. Вместо того, чтобы выбрать простой и надежный путь — взять один из тучи скриптовых языков, который бы сделал все тоже самое, люди создали свое уродство из того, что для задачи изначально вообще не предназначено. Весело, интересно, но мне всегда интересно — зачем? Ведь оно рождено умереть. Я специально сейчас пробежался в гугле — такое ощущение, что интернет вообще не знает про это приложение. При этом, автор, судя по всему, надеется привлечь к созданию карточек других людей. Это — правильно. А вот ставить задачу перед ними учить такую вот ужасть — совсем неправильно.

                Прошу прощения, это ответ rumkin выше.
                  0
                  Возможно, они начали с какого-нибудь простого внешнего API и описания его маппинга с помощью JSON, а потом немного увлеклись :)

                  На iOS есть ограничения по использованию скриптовых языков внутри приложений — вроде бы, нельзя подгружать извне исполняемый код, кроме JavaScript в WebView.
                    0
                    Да, про это я забыл. Но тогда вопрос, почему модераторы пропустили даже это — по факту, это исполняемый код.
                      +3
                      Возможно решили, что пользоваться этим всё равно никто не будет и ущерба бизнесу Эпла не будет :)
                        +2
                        Все оказалось намного проще. Из интернета загружаются только JSON, внутри которых нет функций — просто набор HTML тегов и их атрибуты. Все, что содержит код, скачивается вместе с приложением и лежит среди ресурсов. Все как требует Apple.
                      +2
                      С недавних пор можно подгружать и исполнять JS через JavaScriptCore.

                      Apple Developer Program License Agreement, п. 3.3.2.
                        0
                        Ну так можно весь этот велосипед с самопальным языком программирования отменять и использовать JavaScript.
                          0
                          Хм, там только WebKit framework, т.е. в приложении без вебкита, самому через jsc скачанный код выполнить нельзя.
                    +7
                    День прошёл зря, если не создан новый язык программирования.
                    Но нет, я лучше lua возьму. Или javascript, если нет ограничений по памяти.
                      –2
                      QML лучше всего для этих целей. Непонятно, почему его боятся использовать, ведь крайне мощная штука!
                      • UFO just landed and posted this here
                          +2
                          А что, разве при добавлении нового формата сериализации мы получаем новый язык?
                          Сериализуй это в XML — вот тебе XML-based язык. Сериализуй в LISP — вот LISP-based.
                          Всё-таки язык не форматом хранения в файле текста программы определяется.
                            +1
                            Пойти сделать транскомпилятор в yml что ли.
                              +4
                              А почему нельзя было писать на обычном скриптовом языке, а в JSON положить одну строку с целиковым исходником?
                                +4
                                Ну а что это за программирование такое без велосипедов на костылях?
                                  +6
                                  тут должна быть эта картинка:
                                  Скрытый текст
                                  image
                                0
                                Что за ..?
                                  0
                                  Почему, мистер Андерсон, почему? Во имя чего? Что Вы делаете? Зачем, зачем вы это делаете с JSON?
                                    0
                                    А почему не jsonnet?
                                      0
                                      Потому что иначе заголовок этой публикации звучал бы «Как мы сделали из jsonnet язык программирования». На этом бы различия заканчивались.

                                    Only users with full accounts can post comments. Log in, please.