Статьи

Потоковый контент для не-медиа приложений

Подавляющее большинство веб-приложений и мобильных приложений используют для передачи данных JSON или XML по проводам. Относительно легко спроектировать служебную схему, а текстовые данные на проводе легче отлаживать. Проекты схемы, однако, имеют тенденцию подчеркивать аналитическую перспективу, а не производительность. Например, схема для иерархических данных обычно будет выглядеть так

node     := data children
children := node*
data     := field+
field    := name value
name     := string
value    := string

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

Я не знаю о вас, но я ненавижу ждать всех данных, когда я не хочу их. Когда я нахожусь в режиме просмотра или ручного индексирования [1], я только хочу понять суть и двигаться быстро. Например, если я пролистываю список фильмов, играющих в местном кинотеатре, мне не нужно изображение постера фильма. Мне нужно знать, что есть 6 фильмов, 6 названий и следующие два показа каждого фильма. Когда я остановлюсь на фильме, мне может быть интересно посмотреть рекламный плакат, трейлер и обзоры, и поэтому я буду ждать, пока эти данные заполнят пользовательский интерфейс. (Не заставляйте меня нажимать кнопку «подробнее», пожалуйста!)

Большинство дизайнеров схем создадут что-то вроде этого

movies        := (movie)*
movie         := title rating director casting 
                 poster-url trailer-url movie-reviews 
                 showtimes
movie-reviews := star-rating reviews
director      := person
casting       := person part
person        := string
part          := string
showtimes     := showtime+
showtime      := start-time end-time
start-time    := number ':' number
reviews       := review*
review        := person star-rating comment-string
...

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

Производительность сети не мгновенная. Разработчикам схем необходимо прекратить проектировать структуры данных, как если бы данные мгновенно передавались с хоста на клиент. Мы не делаем это для аудио или видео, и мы не должны делать это с другими данными. Данные на проводе должны быть разработаны как пакеты для явной организации. И его следует заказать так, чтобы обеспечить удобство использования приложения на высоком уровне даже в условиях низкой пропускной способности сети.

В случае списков фильмов, следующая структура данных лучше

movies      := count id* ( title | 
                           showtime | 
                           poster-url | 
                           trailer-url | 
                           ... )*
title       := id 'title' string
showtime    := id 'showtime' timestamp
poster-url  := id 'poster-url' url
trailer-url := id 'trailer-url' url
review      := ...

Здесь связанные данные явно связаны вместе с идентификаторами, тегами и значениями, а не неявно по положению в иерархии. Затем закажите передачу данных клиенту так, чтобы клиент мог использовать  прогрессивное раскрытие.  Теперь пользователь сможет видеть некоторую структуру и некоторый контент и, таким образом, сможет выполнять некоторое взаимодействие с приложением до того, как вся структура и весь контент будут доставлены.

В случае списков фильмов это может выглядеть так

6 m1 m2 m3 m4 m5 m6 ;
# now get the titles and next showtimes for the movies
m1 title Inception ;
m1 showtime 6:30 ; 
m1 showtime 3:10 ; 
m2 title The Sorcerer's Apprentice ;
m2 showtime  4:50 PM ;
m2 showtime  7:20 PM ;
m3 title Despicable Me ;
m3 showtime ... 
m3 showtime ...
m4 title ... ;
m3 showtime ... 
m3 showtime ...
m5 title ... ;
m3 showtime ... 
m3 showtime ...
m6 title The Last Airbender  ;
m3 showtime ... 
m3 showtime ...
# now get the remaining showtimes
m1 showtime 12:00 ; 
m1 showtime 9:40 ;
m2 showtime 11:45 AM ;
m2 showtime 2:15 PM ;
m2 showtime 10:00 PM ;
...
# now get the star-ratings for the movies
...
# etc

Здесь я использую кодировку, разделенную точкой с запятой, чтобы упростить этот пример. Нет причин отказываться от использования JSON или XML в качестве кодировки. Однако вы должны использовать потоковый анализатор JSON или XML, чтобы клиент приложения мог получить данные, как только они поступят.

Этот урок преподал мне Дэвид Дюран, когда мы работали над  MAPA  в Dynamic Diagrams. Визуализация в MAPA — это Java-апплет, отображающий карту местоположений на веб-сайте. Карты, необходимые для отображения канонического пути к локации, локальной структуры сайта вокруг локации и видов страниц там. Структура данных, которую мы использовали для передачи данных, необходимых для отображения карты, имела структурные данные заранее, чтобы апплет мог начать рендеринг карты (в другом потоке). Между тем, информация о каждой странице просочилась и могла быть передана по частям к существующему каркасному каркасу, как только он появился. (Дэвид хотел, чтобы я использовал данные фиксированной ширины, но я не мог заставить себя сделать это. Однако он был прав, и я должен был это сделать.)

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

[1]  Ручная индексация  — это когда у вас есть список из 10 элементов, и вы пролистываете их, пока не найдете нужный элемент. Я уверен, что для этого есть термин «дизайн взаимодействия», но я не знаю, что это такое.