Архитектура интерактивных сайтов

В анонсе серии статей "Интерактивные сайты" я постарался максимально доходчиво изложить свою мотивацию к ей созданию, да и актуальность самой темы, так что сразу к делу!

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

Сразу хочу предупредить, что далеко не всем сайтам такая глобальная интерактивность пойдет на пользу. Если пользователи сайта редко что-либо делают и большую часть времени читают длинные тексты, то, вероятно, этот проект как раз из этой категории: быстрота реакции на клик не так радует, когда большую часть времени приходится работать скроллом. Если Ваш интернет-проект является сайтом с длинным контентом в формате блога, новостей или вики - подумайте лишний раз, прежде чем переделывать весь сайт, вероятно будет достаточно интерактивных комментариев и голосований на AJAX. Для социальных сетей, сайтов знакомств, интернет-магазинов, поисковых систем, корпоративных сайтов и многих других визуально заметная интерактивность определенно станет одним из ключевых конкурентных преимуществ.

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

Архитектура интерактивного сайта

Общие замечания

  • Здесь и далее я буду описывать "среднестатистический" интернет-проект, в зависимости от специфики могут появляться дополнительные компоненты или убираться за ненадобностью упомянутые. Например, если известно, что пользоваться сайтом будут только сотрудники какой-то компании, то помимо замены Интернета на Интранет, можно запросто избавиться и от HTML-интерфейса и всего, что с ним связано - никаким роботам доступ к нему не нужен.
  • Наверное стоит прямым текстом сказать, что:

    • Голубые элементы - компоненты проекта, а серые - внешние.
    • Связи в виде прямых линий означают двусторонний обмен данными, транспорт и формат пока особо не важны.
    • Схема логическая, так что вопросы балансировки нагрузки, отказоустойчивости, репликации и т.п. остались в стороне; за каждым блоком может стоять произвольное количество серверов.
  • Я решил не загромождать схему мониторингом, резервным копированием, почтой, сервисом доменов и прочими хоть и важными, но не связанными напрямую с темой компонентами системы.

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

Клиентская часть

  • Начнем наше путешествие. Пользователь вводит в адресной строке браузера адрес нашего сайта и жмет Enter, инициируя тем самым сначала определение IP-адреса через DNS, а затем и HTTP-запрос к нашему HTML-интерфейсу.
  • Получив в ответ страницу в формате HTML браузер начинает загружать указанные в нем внешние ресурсы, в том числе и Javascript-клиент, которому и передается слово. Сама страница параллельно отрисовывается как и в статичном сайте.
  • Как уже упоминалось выше, некоторые проекты решают не тратить силы на поддержку двух интерфейсов к сайту, жертвуя тем самым доступом большинства роботов и браузеров без поддержки JavaScript. Стартовый HTML-документ в этом случае превращается просто в практически пустой статичный файл, который служит лишь для загрузки клиента.
  • Так как наша цель стоит в интерактивном взаимодействии пользователем, повторять эти действия при каждом переходе на другую страницу - непозволительная роскошь. Кстати, можно начинать думать и общаться не в терминах страниц, а в терминах экранов, которые видит пользователь.
  • Для обеспечения этого JavaScript-клиент должен переопределить стандартные обработчики событий перехода по внутренним ссылкам сайта и отправки форм. Ему нужно отменить стандартный механизм перехода на другую страницу и вместо него отправить запрос через интерфейс сериализованных данных. На основе полученного в ответ сообщения он меняет какую-то часть загруженного ранее HTML-документа, чтобы он соответствовал тому экрану, который ожидал увидеть пользователь. В итоге пользователь видит в браузере ровно ту же картинку, как если бы он ввел тот адрес, на который вела нажатая ссылка, или просто нажал на нее с отключенным JavaScript.
  • Важно не сломать при этом поведение браузера: кнопка "назад" должна работать как обычно, а в адресной строке должны меняться ссылки (это актуально, например, когда пользователь отправляет содержимое адресной строки кому-то по почте или через мессенджер).
  • При ожидании ответа от сервера стоит эмулировать курсор и иконку загрузки страницы, чтобы пользователь не паниковал в случае (пускай и редком) визуально заметных задержек.
  • На резонный вопрос "Почему, собственно, этот трюк обеспечит интерактивность?", ответ хоть и не всегда однозначен, но он все же есть:

    • Сериализованные изменения страницы занимают меньший объем, чем полный HTML со всеми связанными ресурсами, заголовками, версткой и прочим - значительно меньше данных нужно передавать по сети.
    • Как правило, есть возможность держать постоянное соединение между браузером и интерфейсом сериализованных данных, что позволяет не делать лишние HTTP-запросы. Обратная сторона медали - это самое соединение постоянно же использует часть серверных ресурсов, но есть способы минимизировать эти издержки.
    • Для некоторых действий изменения HTML не требуют ответа сервера и могут быть сделаны параллельно с отправкой запроса (например  различные вариации на тему +1 или написание комментария, текст которого можно взять из формы).
    • Как правило, можно предсказать наиболее вероятные переходы по экранам и загрузить необходимые изменения заранее. Хотя этот вопрос скорее из области оптимизации.
    • Таким образом, в большинстве случаев есть техническая возможность снизить время отклика  на действие пользователя с 500-2000 мс в случае неплохо сделанного статического сайта до 20-200 мс., что вполне сопоставимо с откликом десктопного приложения.
  • Как все это сделать на практике - тема следующей статьи из серии.

Серверная часть

  • С серверной точки зрения основным отличием является четкое разделение двух входных точек:
    • HTML-интерфейс отдает готовые документы в ответ на HTTP-запросы.
    • Интерфейс сериализованных данных использует какое-то постоянное соединение, хотя в некоторых случаях целесообразно ограничиться просто асинхронными HTTP-запросами.
  • Если для статичных сайтов полное выделение бизнес-логики в отдельные сервисы - просто хорошее архитектурное решение, то для интерактивных сайтов - это практически необхохимо. Иначе придется реализовывать и поддерживать две копии кода для каждого интерфейса и надеяться, что они постоянно будут оставаться совместимыми и выдавать одинаковый результат.
  • Хорошей практикой является использование какого-то одного протокола общения между компонентами системы, в частности пользовательских интерфейсов с сервисами бизнес-логики и последних друг с другом. Желательно использовать что-то бинарное и с поддержкой разных языков программирования, хотя если весь проект на одной платформе и не планирует это менять - можно использовать и стандартный для этой платформы протокол.
  • Чтобы не включать элементы верстки при передаче через интерфейс сериализованных данных, рекомендую использовать кроссплатформенный формат HTML-шаблонов. Об этом будет отдельная статья.
  • Интерфейс сериализованных данных при необходимости легко может быть адаптирован для использования в роли API для сторонних сервисов или собственных приложений для мобильных платформ или настольных компьютеров.
  • В целом внутренние сервисы общаются с остальными располагающимися на серверной части компонентами системы вполне обычным образом.
  • В статье про серверную часть подробно будет рассматриваться использование брокера сообщений для уведомлений пользователей в реальном времени.

Подводим итоги

  • Глобальная интерактивность сайта требует использования достаточно сложного и комплексного JavaScript-клиента и создания дополнительного более легковесного внешнего инетрфейса на серверной части.
  • По-настоящему мгновенной реакцией сайта смогут насладиться лишь пользователи с современным браузером и относительно широким интернет-каналом. Из-за возможных сетевых задержек или особенностей устаревших браузеров эффект мгновенного перехода все же может теряться, но при должном тестировании реально добиться нормального поведения сайта и в таких ситуациях. Хотя зачастую "проваливание" до обычного режима статичных страниц в подобных ситуациях - вполне резонное решение.
  • Архитектура серверной части проекта в большинстве случаев не требует существенных изменений. Хотя если в ней все было хаотично и не продумано, то создание интерактивного клиента может послужить неплохим поводом пересмотреть и привести в порядок и её.
  • Кроме очевидной потребности в использовании JavaScript для клиента, особых ограничений на используемые технологии и языки программирования, обсуждаемая схема не накладывает.

Эта статья - первая в серии про Интерактивные сайты, автор - Иван Блинков, основано на личном опыте. До встречи на страницах Insight IT!