Спустя месяцы напряжённой работы мы наконец выпустили приложение для 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.

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


Перевод местами достаточно вольный, но не в ущерб смыслу или содержанию. Все, что не относится напрямую к оригиналу, вынесено в примечания. Автор публикации является по совместительству и автором приложения, так что исходный текст является несколько рекламным. Я постарался перенести акцент именно на разработанный язык. За большим количеством ссылок и разнообразных призывов обращайтесь к оригиналу.
С предложениями, пожеланиями и замечаниями, как обычно, в ЛС.

Комментарии (31)


  1. Beholder
    20.06.2015 18:17
    +3

    Какой-нибудь диалект Lisp смотрелся бы лучше.


    1. crmMaster
      20.06.2015 18:52
      +28

      Тут бы любой нормальный язык прогрммирования смотрелся бы лучше


    1. rumkin
      20.06.2015 18:52
      -2

      Задача сводилась к тому чтобы сделать именно из декларативного формата.


      1. creker
        20.06.2015 19:00
        +16

        Только получился почему-то императивный язык, который прилично так изуродовали


        1. rumkin
          20.06.2015 19:10

          Не вижу противоречия. Взяли декларативный формат и разработали правила для описания императивной программы. «Уродство» – следствие имеющихся ограничений формата.


        1. gwer Автор
          20.06.2015 19:24
          +2

          На выходе нужен был JSON. Видимо, поэтому авторы и подумали, почему бы не сделать его и на входе. Требовалось расширить имеющийся инструмент. Объектом вдохновения могли быть, например, препроцессоры CSS: человек, знакомый с CSS, разберется с препроцессором в мгновение ока. Но одно дело — развить формат описания данных в расширенный формат описания данных или расширить язык программирования до языка программирования с большими возможностями. И совсем другое — расширить формат описания данных до языка программирования.

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


        1. marapper
          20.06.2015 23:09

          Точно. IoC в HATEOAS/JSON-API гораздо интереснее в плане сохранения декларативности json, и одновременно передачи api управления поведения приложения.


      1. salas
        21.06.2015 02:08

        Ну, например, если из приведённого JSON (литералов JavaScript) удалить двоеточия, получится валидный edn (литералы Clojure), чем не декларативный формат. На этом этапе разницы практически никакой, но зато можно весь этот "_WTF" заменить на обычные вызовы функций и получить вполне пристойный EDSL. Да, в сущности, и на JavaScript можно было бы, но авторы же хотели иммутабельность и ленивость из коробки?


  1. creker
    20.06.2015 19:18
    +11

    Противоречие тут в другом. Вместо того, чтобы выбрать простой и надежный путь — взять один из тучи скриптовых языков, который бы сделал все тоже самое, люди создали свое уродство из того, что для задачи изначально вообще не предназначено. Весело, интересно, но мне всегда интересно — зачем? Ведь оно рождено умереть. Я специально сейчас пробежался в гугле — такое ощущение, что интернет вообще не знает про это приложение. При этом, автор, судя по всему, надеется привлечь к созданию карточек других людей. Это — правильно. А вот ставить задачу перед ними учить такую вот ужасть — совсем неправильно.

    Прошу прощения, это ответ rumkin выше.


    1. Goodkat
      20.06.2015 19:31

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

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


      1. creker
        20.06.2015 19:39

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


        1. Goodkat
          20.06.2015 19:47
          +3

          Возможно решили, что пользоваться этим всё равно никто не будет и ущерба бизнесу Эпла не будет :)


          1. creker
            20.06.2015 20:05
            +2

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


      1. corristo
        20.06.2015 23:32
        +2

        С недавних пор можно подгружать и исполнять JS через JavaScriptCore.

        Apple Developer Program License Agreement, п. 3.3.2.


        1. Goodkat
          21.06.2015 00:55

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


        1. Antelle
          21.06.2015 12:21

          Хм, там только WebKit framework, т.е. в приложении без вебкита, самому через jsc скачанный код выполнить нельзя.


          1. corristo
            21.06.2015 13:28
            +1

            image


            1. Antelle
              21.06.2015 14:02

              О как, это значит новая редакция, это радует. Я посмотрел в этом документе: только вебкит.


  1. agmt
    20.06.2015 21:06
    +7

    День прошёл зря, если не создан новый язык программирования.
    Но нет, я лучше lua возьму. Или javascript, если нет ограничений по памяти.


  1. QtRoS
    20.06.2015 21:24
    -2

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


  1. deniskreshikhin
    20.06.2015 21:59
    +7

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

    Что бы это стало языком программирования нужна ещё грамматика и лексика.

    А так у каждого js-языка есть своё AST, и там как правило всё в json хранится.


  1. speakingfish
    20.06.2015 22:05
    +2

    А что, разве при добавлении нового формата сериализации мы получаем новый язык?
    Сериализуй это в XML — вот тебе XML-based язык. Сериализуй в LISP — вот LISP-based.
    Всё-таки язык не форматом хранения в файле текста программы определяется.


  1. sandricmora
    20.06.2015 22:40
    +1

    Пойти сделать транскомпилятор в yml что ли.


  1. impwx
    21.06.2015 00:39
    +4

    А почему нельзя было писать на обычном скриптовом языке, а в JSON положить одну строку с целиковым исходником?


    1. gwer Автор
      21.06.2015 01:02
      +4

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


      1. 6opoDuJIo
        21.06.2015 03:16
        +6

        тут должна быть эта картинка:

        Скрытый текст
        image


  1. iDennis
    21.06.2015 16:31

    Что за ..?