Это глава 46 раздела «SDK и UI-библиотеки» моей книги «API». Второе издание книги будет содержать три новых раздела: «Паттерны API», «HTTP API и REST», «SDK и UI‑библиотеки». Если эта работа была для вас полезна, пожалуйста, оцените книгу на GitHub, Amazon или GoodReads. English version on Substack.

В предыдущей главе мы обсудили, каким образом можно упростить разработку сложных компонентов с использованием паттерна «модель». Другой способ обойти сложность «переброса мостов» между несколькими предметными областями, которые нам приходится сводить в рамках одного UI-компонента — это убрать одну из них. Как правило, речь идёт о бизнес-логике: мы можем разработать компоненты полностью абстрактными, и скрыть все трансляции UI-событий в полезные действия вне контроля разработчика.

В такой парадигме код поиска предложений выглядел бы так:

class SearchBox {
  …
  search(query) {
    const markup = await api.search(query);
    this.render(markup);
  }
  …
}

То есть вместо получения машиночитаемых результатов поиска, мы получаем с сервера их готовое представление в виде кода на HTML либо другого (возможно, разработанного специально для нашего SDK) языка разметки.

Этот подход можно обобщить ещё сильнее:

class SearchBox {
  constructor (…) {…}
  stateChange (patch) {
    // Получаем от сервера
    // список действий, которые
    // необходимо выполнить при
    // запрошенном изменении
    let actions = await api
      .getActions(
        this.model,
        patch
      );
    // Применяем действия
    …
  }
}

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

(Примером реализации этой идеи можно считать т.н. «Web 1.0» — сервер присылает готовый контент страницы, а вся интерактивность сводится к переходам по ссылкам.)

Хотя Backend-Driven UI обладает очевидным недостатком в виде требовательности к качеству соединения с сервером, у него есть два очень важных преимущества:

  • возможность с сервера регулировать поведение клиента, в том числе устранять возможные ошибки в бизнес-логике в реальном времени без необходимости обновлять приложение;

  • возможность сэкономить на разработке консистентной и читабельной номенклатуры сущностей публичного SDK, ограничившись минимальным набором доступной функциональности.

Тем не менее, мы не можем не отметить: при том, что любая крупная IT-компания проходит через эту фазу — разработки Backend-Driven UI (они же — «тонкие клиенты») для своих приложений или своих публичных SDK — мы не знаем ни одного заметного на рынке продукта, разработанного в этой парадигме (кроме, разве что, протоколов удалённых терминалов), хотя во многих случаях возникающими сетевыми задержками вполне можно было бы пренебречь. Рискнём сказать, что причины сложившегося положения вещей таковы:

  • разработать серверный код управления UI ничуть не проще, нежели клиентский;

  • современные клиентские устройства предоставляют широкий спектр функциональности, доступной только клиентскому разработчику, от кэшей до анимаций;

    • гибридный код, который частично получает состояние с сервера, частично обогащает его на клиенте, писать гораздо сложнее, чем чистый клиентский (в силу того, что в Backend-Driven UI содержимое ответа сервера для клиента представляет собой «чёрный ящик», для взаимодействия с которым приходится изобретать дополнительные протоколы);

    • отказ от гибридного кода, во-первых, сужает возможности приложения и, во-вторых, фактически переводит клиентское устройство в режим «облачного гейминга», что на сегодня очень дорого и не очень удобно для пользователя;

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

NB: следует различать Backend-Driven UI и технологию серверного рендеринга (SSR). Второе подразумевает, что одно и то же состояние UI (как правило, в виде HTML-разметки или аналогичного декларативного описания) может быть сгенерировано как сервером, так и клиентом. В SSR, однако, подразумевается, что клиент может интерпретировать ответ сервера и извлекать из него семантические данные.

С точки зрения предложения SDK сторонним разработчикам, Backend-Driven UI фактически вынуждает разрабатывать гибридный код (поскольку практика предоставления партнёрам возможности встроиться в функции серверного рендеринга на стороне провайдера API выглядит весьма далёкой от жизнеспособности идеей), и, таким образом, будет страдать от той же проблемы непрозрачности — разработчик не может со своей стороны определить, в каком сейчас состоянии находится визуальный компонент. Как ни странно, этот недостаток одновременно является и достоинством, поскольку вендор API сохраняет возможность на своей стороне производить любые манипуляции с контентом без нарушения обратной совместимости (мы обсудим этот вопрос в главе «Линейка сервисов API»). Таких клиентских API в мире существует довольно много (в первую очередь, разнообразные виджеты, рекламные API и т.д.), но их сложно назвать полноценными SDK.

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


  1. TrueRomanus
    15.09.2023 12:19

    То есть вместо получения машиночитаемых результатов поиска, мы получаем с сервера их готовое представление в виде кода на HTML

    Это очень хорошая идея но ровно до того момента когда появится интерактивность внутри этого представления.

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

    Решив проблему с универсальным UI на каждых чих приезжающий с сервера возникнет совсем другой класс проблем. Сетевых проблем, результатом которых будет либо недогруженный UI или несоответствие версий UI, измененные пути ведущие в 404 и т.п.

    Тем не менее, мы не можем не отметить: при том, что любая крупная IT-компания проходит через эту фазу — разработки Backend-Driven UI (они же — «тонкие клиенты») для своих приложений или своих публичных SDK — мы не знаем ни одного заметного на рынке продукта, разработанного в этой парадигме (кроме, разве что, протоколов удалённых терминалов)

    Тут очень важно понимать что такое "тонкий клиент" по Вашему а то таких технологий может оказаться очень много, например бутстрапер любой MMORPG это тонкий клиент или нет?
    А если мы говорим о вебе то нет ни одного заметного продукта потому что фаза эта закончилась провалом для таких технологий как Flash, Silverlight, Java Applet и других.
    Вместо этого усилия сообщества были направлены на то чтобы все что было в этих технологиях появилось и в web браузере и не надо было кучу тонких клиентов ставить заходя на рандомный сайт. Сейчас никто этим не занят потому что в этом просто нет никакого смысла. Уже даже десктопные приложения делают на технологиях вроде Electron которые по сути web браузер с щепоткой клиентского кода.

    разработать серверный код управления UI ничуть не проще, нежели клиентский;

    Возможно Вы имели ввиду "разрабатывать клиентское приложение работающее не на клиенте а по факту работающее на сервере сложнее"?

    следует различать Backend-Driven UI и технологию серверного рендеринга (SSR). Второе подразумевает, что одно и то же состояние UI (как правило, в виде HTML-разметки или аналогичного декларативного описания) может быть сгенерировано как сервером, так и клиентом. В SSR, однако, подразумевается, что клиент может интерпретировать ответ сервера и извлекать из него семантические данные.

    И чем плох вариант с генерация клиентом?

    Когда соединение с сервером нестабильно или теряется Во что превратится UI? Одно дело UI "на клиенте" он просто покажет крутилку или что-то в таком духе но сам по себе продолжит быть отзывчивым, весь оффлайн функционал продолжит работу. Но в случае с Backend-Driven UI не получиться поставить даже крутилку потому что связь просто пропадет. Сетевые проблемы также могут сильно подпортить UX пользователю он будет либо часто видеть крутилку, либо нажимать на кнопки и другие интерактивные элементы а интеракции не будут происходить.


    1. forgotten Автор
      15.09.2023 12:19

      например бутстрапер любой MMORPG это тонкий клиент или нет?

      Нет. GeForce now — скорее да, и то с некоторой натяжкой. MMORPG всё-таки позволяют кнопки в меню нажимать локальным кодом, а не вызовом сервера.

      разрабатывать клиентское приложение работающее не на клиенте а по факту работающее на сервере сложнее

      Не вижу особой разницы между этими утверждениями


      1. TrueRomanus
        15.09.2023 12:19

        "Нет. GeForce now — скорее да, и то с некоторой натяжкой. MMORPG всё-таки позволяют кнопки в меню нажимать локальным кодом, а не вызовом сервера. "

        Т.е. Backend-Driven UI это когда клиент просто "удаленный рабочий столприложение" который картинку приезжающую с сервера показывает? С клиента только точки где мышка проезжает отсылаются и какие кнопки на ней (мышке) нажимаются? Я все верно понял?


        1. forgotten Автор
          15.09.2023 12:19

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


          1. TrueRomanus
            15.09.2023 12:19

            Объясните пожалуйста отличие "представления для рендеринга" от "семантических данных" пожалуйста.


            1. forgotten Автор
              15.09.2023 12:19

              `<div>Hello, TrueRomanus</div>` — представление для рендеринга
              { "user_name": "TrueRomanus" } — семантические данные


              1. TrueRomanus
                15.09.2023 12:19

                Спасибо за разъяснение. Я думаю за пределами Web такое проворачивать без изобретения своего HTML аналога крайне затруднительно.


                1. forgotten Автор
                  15.09.2023 12:19

                  Я видел множество попыток. И да, получается аналог HTML