Карточки, как независимые интерактивные единицы, показывают, каким будет будущее мобильных интерфейсов.
Когда мы только начали работать над Relevant, нам были ясны лишь две вещи: карточки должны быть красивыми, и они должны быть универсальными. То есть их содержание может формироваться из любого источника информации в сети с минимальными ограничениями. Что до красивости, так она заслуживает отдельной статьи, и здесь мы её касаться не будем, а поговорим именно об универсальности.
Карточки как объекты JSON
Так как карточки Relevant должны быть лёгкими и скачиваемыми, мы решили представлять их в виде JSON-файлов, содержащих инструкции о том, как получить доступ к различным источникам информации и API в сети и как преобразовать полученные данные в содержимое карточек.
Требовалась необычайно гибкая структура карточек, которая бы не усложняла процесс их создания. Должна быть возможность, например, получения от API массива с товарами, а затем и получение подробной информации о каждом из них. Причём получение данных может происходить посредством разных API с последующим сбором всего этого воедино.
Таким образом, стало ясно, что требуется создать универсальный API-агрегатор: гибкий, легко изменяемый и хранящийся во внешних файлах. Это позволит создать экосистему, где карточки смогут развиваться, в отличие от приложений, содержимое которых недоступно для пользователя, так как разработчики просто захардкодили его.
API нестандартны
Веб-сервисы и API представлены в виде самых разных форм. Некоторые API, когда требуется вернуть список, возвращают просто массив, в то время как другие засовывают его куда-то в недра возвращаемого объекта. Одни используют разбиение на страницы, другие принимают явный параметр страницы. [Не совсем ясно, в чем заключается подразумевающаяся разница] Добавьте к этому сотни стандартов формата даты и времени, пару стандартов URL и случайное оборачивание целых и дробных чисел в кавычки. Большинство разработчиков, пытающихся создать систему агрегации многочисленных API, быстро погружаются в многоуровневый ад из блоков if-else.
Нам хотелось чего-то более мощного. Требовалось сделать нашу платформу независимой от качества дизайна API и его данных. После долгих проб и ошибок Relevant Card’s JSON стал выглядеть примерно так:
Большая часть нашей инфраструктуры агрегации 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)
creker
20.06.2015 19:18+11Противоречие тут в другом. Вместо того, чтобы выбрать простой и надежный путь — взять один из тучи скриптовых языков, который бы сделал все тоже самое, люди создали свое уродство из того, что для задачи изначально вообще не предназначено. Весело, интересно, но мне всегда интересно — зачем? Ведь оно рождено умереть. Я специально сейчас пробежался в гугле — такое ощущение, что интернет вообще не знает про это приложение. При этом, автор, судя по всему, надеется привлечь к созданию карточек других людей. Это — правильно. А вот ставить задачу перед ними учить такую вот ужасть — совсем неправильно.
Прошу прощения, это ответ rumkin выше.Goodkat
20.06.2015 19:31Возможно, они начали с какого-нибудь простого внешнего API и описания его маппинга с помощью JSON, а потом немного увлеклись :)
На iOS есть ограничения по использованию скриптовых языков внутри приложений — вроде бы, нельзя подгружать извне исполняемый код, кроме JavaScript в WebView.creker
20.06.2015 19:39Да, про это я забыл. Но тогда вопрос, почему модераторы пропустили даже это — по факту, это исполняемый код.
Goodkat
20.06.2015 19:47+3Возможно решили, что пользоваться этим всё равно никто не будет и ущерба бизнесу Эпла не будет :)
creker
20.06.2015 20:05+2Все оказалось намного проще. Из интернета загружаются только JSON, внутри которых нет функций — просто набор HTML тегов и их атрибуты. Все, что содержит код, скачивается вместе с приложением и лежит среди ресурсов. Все как требует Apple.
corristo
20.06.2015 23:32+2С недавних пор можно подгружать и исполнять JS через JavaScriptCore.
Apple Developer Program License Agreement, п. 3.3.2.Goodkat
21.06.2015 00:55Ну так можно весь этот велосипед с самопальным языком программирования отменять и использовать JavaScript.
Antelle
21.06.2015 12:21Хм, там только WebKit framework, т.е. в приложении без вебкита, самому через jsc скачанный код выполнить нельзя.
corristo
21.06.2015 13:28+1Antelle
21.06.2015 14:02О как, это значит новая редакция, это радует. Я посмотрел в этом документе: только вебкит.
agmt
20.06.2015 21:06+7День прошёл зря, если не создан новый язык программирования.
Но нет, я лучше lua возьму. Или javascript, если нет ограничений по памяти.
QtRoS
20.06.2015 21:24-2QML лучше всего для этих целей. Непонятно, почему его боятся использовать, ведь крайне мощная штука!
deniskreshikhin
20.06.2015 21:59+7По сути это не язык программирования, а голое абстрактное синтаксическое дерево.
Что бы это стало языком программирования нужна ещё грамматика и лексика.
А так у каждого js-языка есть своё AST, и там как правило всё в json хранится.
speakingfish
20.06.2015 22:05+2А что, разве при добавлении нового формата сериализации мы получаем новый язык?
Сериализуй это в XML — вот тебе XML-based язык. Сериализуй в LISP — вот LISP-based.
Всё-таки язык не форматом хранения в файле текста программы определяется.
impwx
21.06.2015 00:39+4А почему нельзя было писать на обычном скриптовом языке, а в JSON положить одну строку с целиковым исходником?
Beholder
Какой-нибудь диалект Lisp смотрелся бы лучше.
crmMaster
Тут бы любой нормальный язык прогрммирования смотрелся бы лучше
rumkin
Задача сводилась к тому чтобы сделать именно из декларативного формата.
creker
Только получился почему-то императивный язык, который прилично так изуродовали
rumkin
Не вижу противоречия. Взяли декларативный формат и разработали правила для описания императивной программы. «Уродство» – следствие имеющихся ограничений формата.
gwer Автор
На выходе нужен был JSON. Видимо, поэтому авторы и подумали, почему бы не сделать его и на входе. Требовалось расширить имеющийся инструмент. Объектом вдохновения могли быть, например, препроцессоры CSS: человек, знакомый с CSS, разберется с препроцессором в мгновение ока. Но одно дело — развить формат описания данных в расширенный формат описания данных или расширить язык программирования до языка программирования с большими возможностями. И совсем другое — расширить формат описания данных до языка программирования.
В простейших случаях, возможно, доля удобства в этом и будет, но только в них. Конструкции получаются громоздкими, а решения проблем, обозначенных как предпосылки к созданию нового языка, я не увидел.
marapper
Точно. IoC в HATEOAS/JSON-API гораздо интереснее в плане сохранения декларативности json, и одновременно передачи api управления поведения приложения.
salas
Ну, например, если из приведённого JSON (литералов JavaScript) удалить двоеточия, получится валидный edn (литералы Clojure), чем не декларативный формат. На этом этапе разницы практически никакой, но зато можно весь этот "_WTF" заменить на обычные вызовы функций и получить вполне пристойный EDSL. Да, в сущности, и на JavaScript можно было бы, но авторы же хотели иммутабельность и ленивость из коробки?