BDUI — это спасение от релизов: «Какие ваши доказательства?»
Если вы видели no-code-проекты, где можно просто блоками перетаскивать интерфейс, то отчасти вы уже знакомы с BDUI-подходом, ведь они по сути и построены на BDUI. Суть в том, что мы делегируем наполнение интерфейса серверу. Фронтенд не отвечает за то, что будет нарисовано, а только определяет список допустимых компонент, которые сервер может показать пользователю. Но в вебе BDUI не очень популярен.
А зря. Ведь в первую очередь он нужен как спасение от релизов.
Но, если быть точнее, он нужен как средство для снижения количества релизов, затрат на разработку и выкатку фичей. Давайте это и обсудим, а также как работает BDUI, разберём примеры, реализованную фичу, которую мы недавно релизили, посмотрим на другие варианты реализации и подведём итоги.
Вряд ли узнаете, как на 100% реализовать или внедрить BDUI в свой проект, ибо это слишком категорично, потому что для каждого проекта всё индивидуально. Но… об этом я и расскажу в моей обзорной «лекции».
Меня зовут Никита, я работаю фронтенд-разработчиком в Альфа-Банке, преподаю в Высшей школе экономики и в Сколтехе (коммуникации). Работаю над проектом Alfa Online, версией мобильного банка. У нас крупный проект, несколько десятков команд и больше сотни разработчиков.
Как оно работает?
Как писал выше, в этом подходе мы делегируем наполнение интерфейса серверу. Фронтенд отвечает только за то, какие есть компоненты, допустимые для отрисовки.
А достигается это за счёт того, что мы определяем так называемые схемы компонентов. Это простые JSON-схемки, которые определяют список допустимых параметров компонента.
Вот, например, самая простая схема, что я смог найти.
{
"type": "object",
"name": "MarkdownView",
"description": "Модель для MarkdownView",
"releaseVersion": {
"ios": "12.29",
"android": "11.66",
"web": "released"
},
"properties": {
"text": {
"type": "string",
"required": true,
"description": "Текст"
},
"padding": {
"&ref": "../../../atoms/EdgeOffsets/EdgeOffsets",
"required": false,
"description": "Отступы"
},
"horizontalAligment": {
"&ref": "../../TextView/v1/HorizontalAligment",
"required": false,
"description": "Горизонтальное выравнивание"
}
}
}
Это отрисовка компонента Markdown
. У него есть поля: версия, когда он релизнут, версия, с которой доступна, и properties
— необходимые поля, чтобы он работал. Согласно этой схеме, у нас есть только одно обязательное поле — текст. Остальные поля не обязательны.
И что с этой схемой делать? Согласно схеме сервер знает, как эти компоненты могут выглядеть, но пока ничего нам не отрисует, ведь нам нужно конвертировать схемы в какую-то понятную для фронтенда сущность.
Эти сущности (у нас) называются конфигурацией. Вот, для примера, также самая простая конфигурация из имеющихся (из предыдущей схемы, соответственно).
{
"type": "MarkdownView",
"content": {
"text": "## Markdown"
}
}
Здесь у нас есть тип и контент.
Тип
Markdown
, которой ссылается на схему, которая была на картинке выше.Контент — текст с одним полем текст. Текст —
required
, соответственно, мы этим текстом наполняемMarkdown
.
Итак, что мы получаем в результате?
Мы пишем конфигурации для сервера.
Сообщаем серверу по каким эндпойнтам он будет отдавать необходимые конфиги (данные для компонента).
Между сервером и фронтом есть согласованные схемы, в соответствии с которыми сервер может отправлять конфигурации.
Конфиг мы получаем в отрисованном виде.
Например, в нашем примере результат будет выглядеть вот так.
Пример не супервпечатляющий, ведь это компонент довольно низкого уровня, но на основе подобных компонентов можно отрисовать что угодно.
«Какие ваши преимущества?»
Консистентность интерфейсов
Напомню, что у нас довольно крупный проект: несколько десятков команд, больше сотни разработчиков, включая три компетенции — iOS, Android, JS. Зачастую эти десятки команд между собой не взаимодействуют ни процессуально, ни по фичевой, ни по кодовой базе.
При этом пользователю не важно, какая команда какую фичу делала. Он видит один проект, в котором фичи на разных экранах не согласованы и реализованы по-разному. И как раз BDUI здесь сильно помогает в том плане, что у нас нет технической возможности сделать какую-то логическую реализацию иначе, чем все остальные. И пользователь будет видеть единообразие.
Единая база конфигураций
Довольно существенный плюс.
В традиционном подходе добавлением элементов на экран в мобильном приложении занимаются Android-разработчик, iOS-разработчик и веб-разработчик. Здесь могут быть нюансы, но в целом картина плюс-минус такая.
В BDUI-подходе у нас есть одна база конфигураций. На каждой платформе есть своя точка входа для BDUI. Мы создаём одну единую конфигурацию, согласно которой все фронты умеют отрисовывать компонент. Соответственно, нам достаточно сделать одну конфигурацию, сервер её пришлёт в необходимую точку входа, и у нас получится интерфейс.
Нет необходимости в релизах
Мы дошли до главной темы статьи.
Это самая крутая вещь в BDUI. Как только мы его настроили, выстроили точки входа и хотим добавить какую-то новую фичу или как-то поправить старую, то нам не нужно делать релиз приложения!
А какая разница фронтенд-разработчику — есть релизы или нет? Пошёл сделал сборку и всё.
Да, но…
Это затраты времени.
Это риски.
Это программная разработка, что тоже «время».
А если мы хотим динамическое изменение и быстрый интерфейс, мы не можем себе позволить постоянно делать релиз, чтобы добавить какой-нибудь нестандартный рекламный баннер.
Лёгкий порог изменений
Покажу на примере недавней фичи. В ней очень много BDUI экранов. Много экранов — это много текста. Много текста — это много опечаток.
В классическом подходе всё происходит так:
Мы закинули тикет в тестирование.
Тестировщик приходит, видит опечатку, возвращает тикет, либо создаёт новый, в зависимости от процесс.
Грустные разработчики увидели на себе баг, пошли править опечатку.
Поправили, сделали сборку.
Тестировщик снова обрадовался, потом расстроился.
Повторить.
Как это реализовано с BDUI? QA не нужно делать никаких процессуальных вещей: зашёл, поправил конфиг, всё. Это занимает значительно меньше времени, чем все процессуальные с моменты с тикетами.
Редактировать конфиги может не только QA. Потенциально любого участника команды можно научить принципам конфигурации и дать такую возможность. Я буду только рад, если конфигами будут заниматься только дизайнеры или QA.
Улучшение TTM
Уже из определения задачи понятно, что для разработки какой-либо функции проще и быстрее поправить JSON-конфигурацию, чем написать код, который будет делать то же самое. И это действительно так — T2M значительно улучшается с BDUI. Для примера расскажу о довольно масштабном проекте, который мы реализовывали пару месяцев назад.
Покажите этот пункт своему менеджеру — он обрадуется.
Пример реализации
Я работаю в команде Комбо-Карты, они совмещают в себе свойства кредитной и дебетовой карт. Нам нужно было объяснить пользователям преимущества нового продукта и показать, как им пользоваться. Для этого мы реализовали виджет-тренер, который представляет собой шесть кнопок (точек входа) и шесть лендингов, отвечающих на тот или иной вопрос.
Каждая кнопка — это статичный компонент с иконкой, текстом и стрелочкой.
Каждый лендинг — это текст, отступы, картинки, раскрывающиеся списки, выпадающие меню. На лендинге есть всё, кроме логики взаимодействия с пользователем.
Как бы мы решали эту задачу в традиционном подходе?
Реализовали бы точку входа для кнопки, где в зависимости от ответа сервера будет отрисовываться та или иная кнопка.
Сделали бы то же самое для лендинга: точка входа, контейнер, запрос на сервер, ответ, отрисовка лендинга в зависимости от ответа.
Верстали бы шесть таких лендингов, даже если бы у нас была бы самая идеальная дизайн-система с идеальными компонентами, которые всё делают за одно нажатие кнопки.
Подход с BDUI.
Для подобных фичей у нас есть внутренняя реализация BDUI-подхода для быстрой отрисовки статичных вещей на низком уровне. Как это работает?
Всё ещё есть сервер и фронт.
Между ними есть согласованный набор компонентов, которые сервер может отправлять на фронт для рендера.
Этот набор компонентов позволяет кастомизировать экран до уровня текста, отступов и цветов.
Такой «метод» подходит для фич без динамической логики, когда нужно просто показать пользователю что-то статичное, и всё взаимодействие ограничивается переходом по кнопке на лендинг.
Что для этого необходимо?
Всё ещё нужна точка входа для кнопки, ибо её не было изначально.
Для лендинга переиспользовали существующую точку входа.
Мы создали новый эндпойнт, который возвращал необходимый лендинг.
Настроили конфигурации для кнопок и лендинга.
По времени это занимало примерно 30 минут на один лендинг и пять минут на кнопку.
И 36 (тридцать шесть) строчек кода.
А в сумме на разработку шести лендингов и шести кнопок ушло около четырёх-пяти часов. При этом это было первое использование технологии, поэтому разобраться в ней заняло чуть больше времени, чем сама разработка фичи.
Подведу итог.
Ключевая разница в том, что при подходе с использованием готовых блоков на фронте нет никакой бизнес-логики. Мы просто добавляем точку входа и говорим, что здесь будет отрисовываться контент с сервера. Вместо того, чтобы программно писать компоненты и добавлять в нашу кодовую базу, мы создаём конфигурации.
Вот пример конфигурации той самой кнопки из примера, которая состоит из двух основных элементов: иконки и текста.
{
"type": "IconView",
"content": {
"icon": { "name": "{{iconName}}"},
"size": "small",
"shape": "noshape"
},
"paddings": {
"top": "zero",
"left": "m",
"right": "zero"
}
},
{
"type": "TextView",
"content": {
"leftText": {
"textContentKind": "plain",
"value": "{{previewHeader}}",
"color": "textColorPrimary",
"typography": "ParagraphPrimarySmall",
"multiline": true,
"maxLineCount": 9
},
"padding": {
"top": "s",
"left": "m",
"bottom": "s",
"right": "zero"
},
"horizontalAligment": "left"
},
"weight": 1
}
На скрине видно, что два элемента массива состоят из низкоуровневых компонентов: IconView
и TextView
. Это как раз то, о чем я говорил в начале:
есть схема, которая описывает низкоуровневые компоненты;
по компонентам собирается конфигурация;
конфигурации затем соединяется в единую большую конфигурацию и получается сложный компонент: кнопка или лендинг.
Такие конфигурации можно создавать очень быстро. Они открывают большие возможности, исходя из того, что нам нужен всего лишь JSON-конфиг. Например, можем создавать конструкторы, чтобы не делать всё вручную, которые мы сейчас активно разрабатываем — инструменты для автоматизации процесса.
Это гораздо проще, чем писать код.
Вернемся к примеру. У нас есть два поля в двойных фигурных скобках: IconView
и PreviewHeader
. Это именно то, что нам нужно, чтобы избавиться от копипаста. Мы можем указать параметры для кнопки, чтобы все кнопки выглядели одинаково, но отличались иконкой и текстом. Чтобы не писать шесть одинаковых колонок, мы можем создать одну конфигурацию и указать ей параметрами иконку и текст, а сервер применяет эту конфигурацию в зависимости от сегмента пользователя.
К слову, мы используем шаблонизатор Jinja, поэтому можем не только использовать параметры, но и делать циклический/условный рендер. И работает это так, что сервер формирует контекст на основе своей логики, применяет его к шаблону, шаблон возвращается на фронт, а фронт их отрисовывает.
Здесь может возникнуть вопрос: «А зачем нам тратить время на сложности, чтобы отрисовывать статичные фичи?» Почему же только статичные? Давайте добавим динамики.
Добавляем динамику и сложную логику
Часто в функциях есть динамика, когда мы хотим, чтобы пользователь взаимодействовал с интерфейсом. В этом нам помогают динамические поля. Концептуально это всё то же самое, но с небольшой разницей в реализации компонентов.
Также есть более сложная логика, когда нужно заполнить форму, подождать, заполнить, подписать и увидеть красивую плашку, что всё готово.
И для такой реализации у нас есть многошаг — более сложная реализация BDUI-подхода. Кроме конфигурации, многошаг хранит состояние пользователя между фичами и всегда отдаёт актуальный экран.
Про каждую из технологий можно много рассказывать. У нас даже на внутренних мероприятиях можно набрать пару докладов на каждую из реализаций, о которых я рассказал. Это довольно обширная тема.
Эволюция Server-Driven UI: динамические поля, хэндлеры и многошаг
Server-Driven UI (SDUI) — это подход для динамичного и гибкого пользовательского интерфейса, когда с…
И мне особенно нравится этот подход, потому что каждая компания реализует его по-своему. Если вы посмотрите доклады других компаний или статьи, вы увидите, что они делают это не так, как мы, и такая свобода творчества, на мой взгляд, очень круто.
Какие здесь минусы?
Первый и очевидный минус — это…
Ограничение в дизайне
В принципе, минус справедлив всегда, когда мы используем какую-то систему компонентов. Но с BDUI это особенно чувствительно, потому что дизайнер не может просто взять и сказать: «Вот этот компонент будет отрисован не так, а чуть по-другому».
Основы BDUI для продуктовых дизайнеров. Шпаргалка
BDUI (Backend Driven User Interface) — это подход к продуктовой разработке, который набирает популяр…
Всё потому, что сервер не сможет отправить неизвестную конфигурацию, а фронт не отрисует то, что не задумывалось изначально. И здесь всегда появляются мысли о том, что нужно использовать существующие компоненты или создавать что-то новое.
Если мы начинаем создавать что-то новое, появляются сложности. Не всё так безрелизно. Если мы хотим создать какой-то новый компонент, о котором фронт ничего не знает, нам всё-таки нужен релиз. То есть новый компонент не сможет сразу проявиться на фронте. Релизы всё-таки нужны, когда мы хотим создавать новые компоненты или менять поведение существующих.
Платформенные ограничения
И не всё так «едино», как хотелось бы.
Есть разные платформенные ограничения, из-за которых мы не можем сделать один контракт для всех — единую конфигурацию. Сейчас нам иногда всё ещё приходится создавать конфигурации под каждую платформу. Нам проще в том, что для одной компетенции делается конфиг, а потом под остальные адаптируем, но всё равно это разные конфигурации.
Требует насмотренности
Когда новый разработчик приходит и видит обилие новых технологий, нужно иметь большую насмотренность, чтобы разобраться во всём этом и приносить пользу сразу.
Долгая разработка на старте
Самый серьёзный минус, на мой взгляд.
Технических ограничений нет. Это не стандартизированный подход. Каждая компания реализует его по-своему. Вы можете сделать свои конфигурации, которые фронт будет понимать и реализовывать: и анимации, и виджеты, и многошаги, и нестандартные пользовательские сценарии.
Как катить фичи без релизов. Часть 1: про виджеты
Backend-Driven UI — это подход для динамичного и гибкого пользовательского интерфейса, в которой бэк…
Но нужно очень хорошо подумать, что вы хотите реализовывать с помощью BDUI, прежде чем внедрять. Нужно подумать о том:
как будут вести себя компоненты,
как будет проходить процесс добавления новых точек ухода,
продумать много моментов в дизайне, так, чтобы это можно было легко переложить на конфиги,
и очень многое того, что специфично для вашего проекта.
Поэтому, если этот пункт сделать хорошо, остальные минусы будут не так сильно влиять, как если сделать плохо.
Итого
Можно ли обойтись без BDUI? Можно. BDUI — это довольно гибкий инструмент, который можно использовать где угодно. И если подходить к нему с пониманием, где он нужен, то всё будет работать прекрасно. Главное помнить, что это просто инструмент.
Изучите другие наши статьи по теме:
Как катить фичи без релизов. Часть 2: про низкоуровневый Server Driven UI
Привет, меня зовут Елена Яновская , 5 лет в iOS-разработке, TechLead iOS в Альфа-Банке. Участвую в р…
BDUI аналитика, или Почему нельзя просто взять и отправить значения динамических полей в трекер
Привет, меня зовут Анна Саботович , я техлид в Альфа-Банке (команда платежей и переводов), отвечаю з…
Также подписывайтесь на Телеграм-канал Alfa Digital — там мы постим новости, опросы, видео с митапов, краткие выжимки из статей, иногда шутим.