BDUI (Backend Driven User Interface) — это подход к продуктовой разработке, который набирает популярность в больших компаниях и командах. На конференциях разработчики крупнейших российских и зарубежных продуктов рассказывают о том, как внедряют и развивают фреймворк для решения своих задач. На момент написания статьи 8 из 10 сценариев в каналах Альфы для физлиц (мобильное приложение и онлайн-банк для веба) реализуется на фреймворке BDUI. Эту технологию используют AirBnb, Lyft, Alibaba, Озон, Х5, Авито, МТС, Сбер, ВкусВилл, Циан и другие продукты, а Яндекс называет BDUI новым стандартом разработки.
Пожалуй, самый главный плюс BDUI — возможность обновлять экраны мобильного приложения без релиза новых версий этого приложения в сторах.
Причём обновлять не только на уровне значений переменных, как в классике, а прям целиком: менять состав компонентов, их порядок, стили, последовательность экранов в многошаговых сценариях, пользовательские механики и принципы взаимодействия между элементами на экране и сервером.
Это позволяет поддерживать актуальность ключевых экранов даже в старых версиях приложений. Для продуктов, приложения которых были удалены из сторов, это особенно важно. А ещё BDUI позволяет бизнесу проще реализовать единую логику работы сервисов на всех платформах (iOS, Android, Web), быстрее проводить А/В тесты и значительно сократить затраты на фронтовую разработку.
В то же время для продуктового дизайнера, который впервые сталкивается с BDUI, использование этой технологии в проекте, над которым он работает — прежде всего список новых ограничений, которые ему теперь нужно учитывать. Можно было бы выучить этот список, но всё усложняется тем, что зачастую он нигде не прописан. А ещё он регулярно обновляется. В общем, звучит не очень.
Мы верим, что понимание природы ограничений BDUI и умение работать с источниками истины (о которых поговорим позже) — отличная альтернатива выучиванию их наизусть. Поэтому в статье опишем самое важное, что нужно знать и учитывать продуктовому дизайнеру, если проект, над которым он работает, будет реализован на BDUI:
- в чём суть BDUI, и чем он отличается от классического подхода к разработке;
- что такое контракт экрана, контракт компонента, и как с ним работать дизайнеру;
- как дизайнеру читать JSON.
Также кратко поделимся своим опытом внедрения BDUI в дизайн-процессы и дадим несколько рекомендаций для тех, кто только начинает делать это у себя в продукте или команде.
Материал будет полезен в первую очередь тем, кто уже работает с BDUI и хочет восполнить пробелы в базовых вопросах. Но также поможет погрузиться в тему с нуля всем, для кого это актуально.
Примеры, на которых будем строить статью, будут относиться к мобильному приложению, но все основные описываемые принципы актуальны и для веба.
Примечание. Вы также можете встретить термин SDUI (Server Driven User Interface) — по сути это то же самое, отличие только в названии. По нашим наблюдениям, термин BDUI чаще используется в отечественных статьях, выступлениях, на конфах. В зарубежных чаще встречается SDUI. В рамках статьи мы будем говорить «BDUI».
Часть 1: Как устроен BDUI
Если погуглить определение BDUI, то найдётся много формулировок. Усреднённая звучит так:
BDUI — это подход к разработке приложений, при котором бэкенд управляет как данными приложения, так и его внешним видом и поведением.
Давайте разберёмся, как это происходит, и чем отличается от классического подхода, с которым мы привыкли иметь дело. Возьмём для примера несложный экран пользовательского шаблона оплаты коммунальных услуг:
Итак, дизайнер собрал макет и передал разработчику. Посмотрим, как этот экран будет реализован от макета до прода в обоих подходах.
Реализация экрана в классическом подходе
Получив макет, разработчик создаёт в структуре приложения новый экран:
Затем разработчик вручную верстает экран по макету. В идеале, использует для этого компоненты из дизайн-системы продукта. Но если дизайнер аргументированно где-то добавил кастома, например, изменил в компоненте стили или вообще собрал что-то не на компонентах, ничего страшного — технически можно сверстать это локально для нашего экрана.
Часть компонентов содержит переменные. В частности, для каждого клиента на этом экране будут отображаться свои: логотип, название подписки, название компании, номер лицевого счёта и параметры счёта списания. Для них разработчик задаёт стили по макету, но самих значений пока нет — их нам нужно будет запрашивать с сервера в момент загрузки экрана. Поэтому на данном этапе экран выглядит, условно, так:
Так как получение переменных занимает определённое время, при загрузке экрана нам нужно показать клиенту, что эта загрузка происходит. Для этого дизайнер подготовил отдельное состояние экрана со скелетонизацией каждого элемента:
Разработчик сверстал состояние экрана со скелетоном и, по сути, у нас есть всё, чтобы клиент увидел готовый экран на проде:
Готово! Теперь посмотрим, как будет выглядеть аналогичный процесс, если экран реализуется на BDUI.
Реализация того же экрана в BDUI подходе
Разработчик также создаёт экран в структуре приложения. Но уже ничего не верстает вручную. Всю основную информацию про экран: состав компонентов, которые нужно отрисовать, их расположение и параметры, — мы получим с сервера в момент загрузки. А дальше экран сам отобразится в нужном виде.
То есть на этапе, пока мы ничего не получили с сервера, экран выглядит просто как пустой слот:
И так как заранее наш экран ничего не знает про то, что ему нужно будет отобразить, в момент загрузки, мы не сможем показать кастомный скелетон. Сможем* показать только лоадер:
Получив список компонентов, наш экран «идёт» в дизайн-систему, и, как из коробки с Лего, берёт для сборки интерфейса всё, что ему необходимо:
В итоге клиент получает готовый экран:
Итак:
- В классическом подходе структура и компоненты каждого экрана зашиваются на фронте. С сервера мы получаем только значения переменных.
- В BDUI подходе у нас есть универсальный экран, который сможет отрисовать любой контент в зависимости от того, что прислал сервер.
Теперь разберёмся с важными нюансами. Они кроются в моменте обработки контракта на стороне фронта.
Контракт экрана и контракт компонента
Ответ, который мы получим с сервера в момент загрузки экрана, называется контрактом экрана.
Легко запомнить через такую ассоциацию: фронтенд и бэкенд договорились о том, что и как нужно показать на экране — заключили «контракт».
В BDUI самый популярный формат такого контракта — JSON. Это простой текстовый формат с несложными разметкой и синтаксисом.
Среди прочих характеристик экрана контракт содержит список компонентов, которые нужно отобразить, все их параметры и расположение на экране относительно друг друга. В упрощённом виде выглядеть это может, например, так:
Если вы разобрались с тем, как в Фигме устроен автолейаут и переменные, то чтение JSON точно вам под силу. Хотя на первый взгляд этот формат выглядит не слишком дружелюбно. Не беспокойтесь — чуть дальше будет большой блок о том, как читать JSON
Все параметры компонентов выглядят как текстовая пара в виде “ключ”: “значение” — это стандартное описание сущностей в разметке JSON:
Взглянув на контракт нашего экрана, можно интуитивно догадаться, что на экране должны отобразиться пять компонентов — хедер, ячейка, селект счёта списания и два инпута с определёнными в контракте параметрами:
Но возникает вопрос: как фронт понимает, что приходит в контракте? Как он соотносит параметры из контракта с параметрами компонента, который берёт из дизайн-системы?
Чтобы магия произошла, в дизайн-системе создаётся отдельный репозиторий. Для каждого компонента, который может прийти в контракте экрана, в нём заводится отдельная папка:
В этой папке, помимо прочих файлов, хранится контракт компонента — JSON — с описанием всех его параметров и их возможных значений:
В примере выше контрактом компонента является файл IconView.json. Сам контракт компонента выглядит следующим образом:
Как читать код из контрактов, мы подробно расскажем дальше. Пока смотрим базовые моменты, ориентируемся интуитивно. Вчитываться в детали не нужно.
В примере выше видно, как помимо технической информации, в контракте компонента IconView описываются его свойства — основная иконка, цвет фона, иконка для фона, размер и так далее.
Дальше разработчикам остаётся научить компонент интерпретировать эти свойства. То есть установить взаимосвязь между, скажем, параметром Size со значением Small для компонента иконки и его размерностью Small в компоненте дизайн-системы:
Если компонент иконки научили правильно интерпретировать это свойство, то при загрузке фронт корректно отрисует его в одной из трёх размерностей — в той, которая придёт в контракте экрана.
В зависимости от того, как реализован BDUI в конкретном продукте, один и тот же компонент может поддерживать разный набор свойств. Их список зависит от задач, для которых используется BDUI и необходимой гибкости в настройке компонентов.
Например, продукт реализует лендинги на BDUI. Тогда у нас должна быть возможность гибко настраивать компоненты. Так, для иконок важно иметь возможность выбирать из нескольких вариантов размера, управлять цветом фона, добавлять какие-нибудь аддоны сбоку, прокидывать на фон изображение и т.д. В этом случае в контракте экрана мы будем присылать сразу много параметров для иконки, а сам компонент будет уметь эти параметры интерпретировать и отрисовывать как надо:
А какой-то другой продукт собирает на BDUI универсальные формы платежей, где от похожей иконки не требуется большая гибкость. И список её параметров в контракте экрана будет совсем небольшим:
Соответственно, контракты компонента иконки из примеров выше могут быть разными. В обоих случаях в них будет описано, какой размер может принимать иконка и какая иконка из пака должна отобразиться. Но в контракте иконки из первого примера также будет описано, каких цветов она может быть, какой формы бывает её фон и какое изображение можно в него прокинуть, а также что можно отобразить в верхнем углу.
Параметры компонента, которые не прописаны в его контракте, зашиваются на фронте. То есть ими нельзя управлять через контракт экрана. Это ещё один важный момент для понимания дизайнером.
Во втором примере с иконкой выше кроме размера и имени иконки, которые описаны в контракте, у неё есть определённый цвет фона и основного элемента. А также фон имеет определённую форму. Эти параметры зашиты на фронте и будут одинаковыми для всех иконок в такой реализации компонента.
Рассмотрим ещё один пример. Возьмём два варианта реализации простой ячейки с разным набором параметров, которые описаны для неё в контракте:
Пока мы не разобрались с нюансами чтения контрактов, обратите внимание просто на количество свойств, указанных для лейбла и подписи в обоих случаях.
В первом варианте для обоих текстовых элементов определяется только тип значения — “type”: “string”. То есть цвет и стиль типографики каждого элемента в этом случае зашиты на фронте. Если в дизайне мы их изменим, применить эти изменения не получится.
А во втором варианте эти параметры содержатся в контракте компонента. Это значит, что дизайнер может выбрать любой токен типографики и цвета из реализованных в дизайн-системе и поддерживаемый в BDUI, а сервер сможет прислать его значение в контракте экрана, в результате чего фронт отрисует ячейку с нужными стилями:
При этом, и в первом, и во втором случае, на фронте зашиты отступ между текстовыми элементами и паддинги на уровне всего компонента — их нет в контракте. Значит они будут всегда одинаковыми, и влиять на них мы не можем.
Точнее так. Мы можем изменить зашитые на фронте значения отступов, но тогда они обновятся не только в нашем проекте, но и во всех других, где используется компонент. Если мы идём по этому пути, нужно обязательно согласовать изменения со всеми, кого они могут затронуть.
Здесь мы видим ещё одно отличие BDUI от классического подхода. В BDUI нет возможности быстренько подкрутить стили на фронте.
Всё строго: есть компонент в дизайн-системе, есть описание его возможностей в контракте компонента. Если хотим выйти за эти рамки — нужно дорабатывать и контракт компонента, и его фронтовую реализацию в дизайн-системе.
Например, контракт компонента предполагает возможность влиять только на значение текста в компоненте. А мы хотим иметь возможность влиять и на его цвет. Значит нам нужно доработать контракт компонента так, чтобы в ней появилось свойство, которое отвечает за цвет, и научить компонент на фронте это свойство правильно интерпретировать.
Когда BDUI в продукте реализуется сразу под задачи многих команд и бизнес стремится сохранить консистентность решений в интерфейсах, внесение изменений в контракты компонентов становится бюрократичным: нам важно, чтобы наши изменения не поломали уже реализованные фичи, не усложнили жизнь другим командам, и чтобы они не выбивались из паттернов продукта. Приходится проходить этапы обсуждений и согласований.
Поэтому внесение изменений в компоненты в BDUI — это, как правило, не быстро.
По этой причине команды дизайн-систем стремятся заложить в BDUI компоненты максимум гибкости на самом старте их разработки. Так в дальнейшем не придётся тратить время на каждую мелкую корректировку.
Для дизайнеров это означает, например, что в библиотеке могут появляться компоненты, которые представляют из себя набор слотов. Например, таких:
В такие слоты можно прокинуть любой другой BDUI компонент, и даже его же самого. Такие компоненты позволяют реализовать очень сложную кастомную вёрстку.
В целом, в разработке BDUI компонентов есть два возможных подхода.
В первом эти компоненты изначально разрабатываются чисто под BDUI: создаётся отдельная библиотека на фронте и в Фигме, и компоненты умеют ровно то, чему их научили.
Этот подход наиболее простой для дизайнеров — берём компоненты из нужной библиотеки в макеты, читаем их спецификацию, настраиваем в рамках того, что заложено дизайн-системой в сборку.
Во втором подходе отдельные библиотеки для BDUI не создаются.
Вместо этого разработчики пишут контракты для уже существующих в дизайн-системе компонентов и учат их правильно отрисовываться на BDUI экранах. Но при этом в контракт компонента могут быть добавлены не все его свойства, а только часть. Для дизайнеров это сложнее — в макеты нужно брать компоненты из обычной либы, но они могут уметь уже не всё, что заложено в их сборку, а только то, что разработчики заложили в их контракты.
Условно, дизайнер берёт в макет компонент ячейки, который из коробки умеет отображать три строки текстовых элементов. А оказывается, что в BDUI контракте этой ячейки заложено только отображение двух строк. Дизайнеру нужно знать об этом ограничении заранее.
Напишите в комментах, если вам интересно узнать, как команда дизайн-системы Альфы помогает продуктовым дизайнерам не запутаться в этих ограничениях :)
Резюмируем
Вот, что мы с вами узнали:
- В BDUI существуют понятия контракта экрана и контракта компонента. Контракт экрана — это описание списка, расположения и параметров всех компонентов на нём. Он возникает, когда фронт запрашивает данные для отрисовки экрана, а сервер их формирует и присылает. А контракт компонента — это файл, который хранится в отдельном репозитории дизайн-системы. В нём описаны все свойства компонента, которые поддерживаются в BDUI, и их возможные значения, которые могут прийти в контракте экрана. И то, и другое описывается в формате JSON.
- Параметры компонентов, на которые мы можем влиять как дизайнеры, ограничиваются тем, что описано в их контрактах. Если BDUI реализуется с использованием уже существующей библиотеки компонентов, то дизайнеру важно знать, какие возможности этих компонентов поддерживаются в BDUI, а какие нет.
- Свойства компонента, которые не описаны в его контракте, зашиваются на фронте. Управлять ими не получится. Если изменим значения на фронте, изменения отразятся во всех проектах, где используется компонент. Это как изменить мастер-компонент в фигме.
- В BDUI невозможно что-либо подкрутить на фронте. Если хотим, чтобы компонент мог принять нужное нам состояние или стили — нужно доработать его компонент и научить фронт обрабатывать новые параметры. Это требует времени, особенно если нужно согласовывать изменения с другими командами.
По опыту дизайнеров Альфы мы видим, что понимание дизайнером базовых особенностей технологии, а также умение найти в репозитории контракт нужного компонента и правильно интерпретировать информацию из него, наиболее важные навыки при подготовке макетов под BDUI сценарии. С ними дизайнер проектирует экраны осознанно, с учётом существующих возможностей и ограничений, обсуждает решения с разработчиками и аналитиками команды на одном языке, понимает к кому и с чем идти, если на дизайн-ревью проявляются расхождения с макетом.
В целом команда в этом случае тратит меньше времени на реализацию проекта и готовит более продуманное и масштабируемое решение.
Закрепим на примере то, что узнали выше
Предположим, дизайнер передал макет экрана в разработку, и через какое-то время разработчик скидывает ему ссылку на тестовую ветку для проведения дизайн-ревью. Результат отличается от макета:
Если дизайнер не знаком с особенностями BDUI, он может завести задачу на исправление расхождений и вернуть разработчику экран на доработку. Разработчик ответит, что сделать как на макете не получится, потому что у нас ведь BDUI.
Дальнейшее развитие событий может отличаться в зависимости от инициативности участников процесса. Здорово, если дизайнер поинтересуется, что это за ограничения всплыли, как узнать их полный список и можно ли что-то с этим сделать. Если разработчик поддержит и объяснит — команда сможет в итоге (пусть даже не в рамках этой задачи) согласовать улучшения в BDUI на уровне всего продукта, чтобы можно было реализовать целевую версию как на макете.
А зная особенности BDUI, и получив результат из примера выше, дизайнер сделает такие выводы:
- В хедере стоит выравнивание не по центру, и нет серой подложки. Но сам компонент в дизайн-системе это умеет. Значит, либо в контракте экрана приходят неверные значения у свойств, которые отвечают за цвет подложки и выравнивание, либо этих свойств нет в контракте компонента, и на фронте зашит единственный вариант отображения. Чтобы это поправить, нужно предложить доработать контракт компонента.
- Название компании в подзаголовке написано капсом. У нас нет свойства, которое бы регулировало это. Значит, в контракте экрана значение для этого текста приходит сразу в таком виде. Чтобы это поправить, нужно изменить написание названий компаний на сервере. Но надо выяснить, можем ли мы на это влиять, или эти значения приходят от сторонней организации (в случае с Платежами это может быть именно так, и влиять на подобные моменты мы, к сожалению, не всегда можем).
- В итоговой форме отличается состав полей, а в показаниях счётчика появился хинт. Значит, в таком виде всё приходит с сервера. Здесь аналогично — нужно выяснить, можем ли мы влиять на это, либо мы получаем такой контракт от сторонней организации.
Как видите, действия дизайнера становятся более осознанными, становится понятно, что вообще делать в такой ситуации. А в следующей части статьи мы подробно расскажем, как дизайнеру читать JSON и работать с контрактом компонента.
Часть 2: Как дизайнеру читать JSON
Итак, мы выяснили, что у каждого BDUI-компонента есть набор параметров (то есть свойств и их значений), которые определяют, как он будет выглядеть и вести себя на фронте. Например, чтобы на фронте отрисовалась нужная иконка, нам нужно описать её название, цвет и размер — это свойства иконки.
А конкретные название иконки из каталога и токены цвета и размера — это значения свойств для той иконки, которую нам нужно отобразить.
В JSON свойства называют ключами. Ключи и значения каждого объекта описываются парами через двоеточие. Мы уже видели это в примерах выше:
Чтобы было понятно, что к чему относится, в разметке JSON проставляются фигурные скобки, которые объединяют свойства одного объекта. А каждый новый уровень иерархии отбивается дополнительным пробелом слева:
Сразу оговоримся. Далее в примерах мы будем используем упрощённый нейминг свойств и их значений. В компании, где вы работаете, он скорее всего будет отличаться. Условно, в примерах свойство, отвечающее за размер, может называться Size и иметь значения Small, Medium и Large. А в ваших контрактах то же свойство может называться ComponentSize и иметь значения S, M и L.
Это не так важно, потому что синтаксис и разметка JSON остаются при этом универсальными. С ними нам как раз и предстоит разобраться, чтобы в дальнейшем уметь выделять из контрактов экранов и компонентов нужные объекты, и правильно интерпретировать тип и значения их свойств.
Итак, для начала разберёмся, какими бывают ключи и значения.
Ключи и значения в JSON
Ключ в JSON — это всегда строковая переменная. Это значит, что она может задаваться только символами алфавита ("size", "shape", "color", и так далее).
А вот значение может быть как строковой, так и числовой, и логической переменной, а также объектом, массивом или null-константой. Не пугайтесь, сейчас разберёмся, что всё это значит.
Строковые переменные (string)
Строковые переменные всегда текстовые, и используются для указания названий токенов, текстовых значений, имён элементов из ассетов и т.д. В разметке JSON они оформляются кавычками:
В этом примере и ключ, и значение — строковые переменные.
Числовые переменные (number)
Это всегда число, как видно из названия. Используются, если нужно обозначить количество чего-либо. Например, максимальное или минимальное количество строк текста. Выводится в коде без кавычек:
Логические переменные (boolean)
Здесь может быть всего два значения — true или false. Нужны, когда какой-либо признак компонента может быть включен или выключен. Яркий пример — свойство required, которое определяет, обязательно ли инпут должен быть заполнен перед отправкой формы:
Вы наверное обратили внимание, что разные переменные в коде выделяются разным цветом. Это сделано чисто для удобства чтения, чтобы было проще понимать, что где описано. Какой-то прямой взаимосвязи между конкретным цветом и конкретным типом переменной нет, цвет может быть любым.
Объекты (object)
Объект — это список всех параметров сложного элемента. То есть, если элемент нельзя описать описать одной переменной, он будет описан объектом.
Объекты оформляются в коде фигурными скобками. В примере ниже заголовок описывается сразу несколькими параметрами — у него есть текстовое значение, возможность иметь ограничение по строкам, применить разный цвет и стиль типографики. Поэтому в этом случае значение свойства "title" является объектом:
Объекты — это неупорядоченные списки. То есть между элементами этих списков нет других взаимосвязей кроме того, что они описывают какой-то один объект. Элементы списка внутри объекта могут располагаться в любом порядке.
Массивы (array)
Массив — это тоже список, но в отличие от объекта этот список упорядоченный.
В контрактах экранов массивы используются, чтобы показать, в каком порядке должны отображаться однородные элементы внутри объектов. Сам список компонентов на экране тоже является массивом — в каком порядке элементы этого массива будут расположены в коде, в таком отобразятся и на экране. В коде массивы оформляются квадратными скобками:
А в контрактах компонентов массивы используются для перечисления возможных вариантов значения какого-то одного свойства. Например:
Null-константы (null)
Это всегда null в значении свойства в коде. Используются в контрактах экранов, когда нужно показать пустое состояние свойства. Например, нам нужно, чтобы цвет фона какого-либо элемента был прозрачным. Тогда разработчик пропишет нулевую переменную, что равносильно отсутствию данного ключа в JSON:
Ура! С типами переменных мы разобрались, теперь посмотрим, как это всё выглядит в контрактах экранов и компонентов.
Читаем контракт экрана
Как мы помним, контракт экрана описывает, какие компоненты должны прийти, как они расположены на экране, а также параметры этих компонентов.
На самом деле, помимо этого в контракте приходит и другая информация про экран. Но с ней продуктовым дизайнерам работать необязательно. А вот если вы дизайнер из команды дизайн-системы, то очень желательно уметь это делать. Напишите в комментах, если хотите про это отдельную статью :)
Блок с компонентами может быть выделен в контракте в отдельный объект. Например, в Альфе этот объект называется Content:
В этом случае нам, как дизайнерам, проще ориентироваться в таком контракте. Но может быть так, что информация про компоненты лежит просто на одном уровне с другими параметрами экрана, или выделена как-то иначе. Мы рассмотрим в примерах нашу реализацию.
Мы видим, что в значении свойства Content открывается фигурная скобка. Как мы помним, фигурные скобки в JSON означают, что перед нами объект. Значит то, что идёт в коде на следующем уровне иерархии — это параметры нашего объекта, а именно:
- “type”,
- “axis”,
- “alignment”,
- “children”.
Интуитивно можно догадаться, что значения первых трёх свойств означают, что контент нашего экрана — это некий стэк из элементов с вертикальным их расположением и выравниванием по левому краю. Но мы чуть позже сходим посмотреть контракт компонента ItemStack, чтобы точно в этом убедиться. Именно так нужно поступать, если видишь в контракте экрана что-то неоднозначное.
Значение свойства Children находится в квадратных скобках. Значит, это массив. Элементы будут отображены на экране в той последовательности, в какой они расположены в этом массиве. Смотрим, что расположено на следующем уровне иерархии в коде: изображение, стэк элементов, текст и кнопка.
Изображение (image) описано тремя свойствами. Причём все они имеют разный тип переменной в значении:
Соотношение сторон (ratio) описывается числовой переменной. В нашем случае это «0.5», то есть соотношение 1:2. Но могло прийти и любое другое соотношение. К примеру, «1», если бы дизайнер решил сделать изображение квадратным:
Дальше идёт свойство rounded с логической переменной в значении — то есть изображение может либо иметь скругление углов, либо не иметь. Конкретный размер скругления не определяется, значит он зашит на фронте:
В значении свойства url передаётся просто строка со ссылкой на изображение:
После изображения идёт itemStack. Аналогичный мы уже видели на верхнем уровне со списком компонентов. В данном случае элементы в стэке располагаются горизонтально и с выравниванием по центру:
Дочерние элементы стэка (children) — текст и иконка. Для текста определены его цвет, стиль типографики и значение:
Для иконки — имя в наборе, цвет и размер:
После стэка с текстом и иконкой выводятся компоненты текста и кнопки:
Компонент текста мы уже видели выше, здесь все параметры — те же. Кнопка описывается тремя свойствами со строковыми переменными. Для неё указывается размер, стиль отображения и подпись.
Итак, мы с вами посмотрели, как искать и интерпретировать в контракте экрана блок с описанием компонентов. Резюмируем основной принцип: ищем названия компонентов в коде, и далее, уровень за уровнем, изучаем их параметры.
Экран, отрисованный на фронте по контракту из примера выше, выглядит так:
Все компоненты на месте, но выглядит плохо — всё слиплось, очевидно не хватает паддингов. Давайте попробуем понять, почему так получилось, и можем ли мы на это повлиять. Для этого идём изучать контракты наших компонентов.
Читаем контракт компонента
Первым делом нужно узнать у разработчиков, как попасть в репозиторий, где лежат контракты BDUI компонентов. Возможно, придётся получить для этого отдельные доступы. После прохождения этого квеста, находим в общей папке репозитория папочку с нужным компонентом. Для начала найдём itemStack:
В папочке компонента ищем файл .json с названием компонента в имени:
Структура самого файла подчиняется тем же правилам построения JSON, которые мы видели в контракте экрана. Описание компонента построено иерархическим образом:
Наверху списка параметров в этом примере мы видим “type”: “object”. Также ниже в описании свойства children встречается “type”: “array”. Это указание на то, какой тип переменной используется для описания значения. Условно, если в контракте компонента для какого-либо элемента указывается “type”: “object”, значит в контракте экрана этот компонент будет описан объектом. А если “type”: “string”, то в контракте экрана это будет просто текстовая строка.
Запомните обозначения типов переменных в коде, чтобы они не смущали при его чтении.
Но нас в контракте компонента интересует в первую очередь блок Properties, в котором перечисляются все его свойства и их возможные значения:
Если пройтись взглядом по следующему уровню иерархии после Properties в коде, мы увидим, что ItemStack может быть описан четырьмя свойствами:
Давайте на примерах этих свойств разберёмся с особенностями описаний параметров в контрактах компонентов.
Начнём с ключей, характерных для таких контрактов.
Ключ #ref
Часто параметры компонентов нельзя описать простой переменной. Для этого приходится использовать более сложные значения — объекты или массивы. При этом, чтобы список свойств не усложнялся дополнительными уровнями иерархии и элементами, описание этих объектов и массивов выносят отдельно — либо в этот же документ, либо в отдельный файл. А в значениях свойств, которые они описывают, указывают путь, где их искать.
В значении ключа “$ref” может стоять ссылка с # в начале:
Это значит, что описание возможных значений свойства находится ниже в этом же файле контракта. Путь # / definitions / Axis означает, что нужно искать блок Definitions, а в нём объект Axis:
Бывает также, что ссылка указывается с “.. / .. / ..” в начале:
В таких ссылках указывается путь к отдельному файлу с описанием значения свойства. Конкретно в примере выше свойство items описывает, какими характеристиками может обладать элемент массива. Из контракта мы видим, что список этих характеристик можно найти в файле LayoutElement.json, который лежит в папке Common в репозитории с контрактами компонентов (конкретно этот путь — специфика Альфы, у вас может быть иначе).
Часто описания значений выделяются в отдельные файлы, чтобы было удобно ссылаться на них сразу из многих контрактов. Например, цвет — универсальное свойство, которое есть у текста, иконки, фона в карточке и многих других элементов. А токенов цвета в дизайн-системе несколько десятков. Чтобы не добавлять этот список в блок Defenitions контракта каждого отдельного компонента, создаётся отдельный файл с ним.
Итак, ссылки “$ref” в контрактах компонентов означают, что интересующее нас свойство описано либо ниже в этом же файле, либо в отдельном файле. Путь указывается в значении свойства.
Ключ required
Говорит об обязательности данного параметра и может принимать только два значения: true или false. Является обязательным для каждого параметра. Из контракта нашего компонента itemStack мы видим, что свойства axis, alignment и children для него обязательные. А свойство paddings — нет:
Если свойство не является обязательным, то оно может не прийти для компонента в контракте экрана — фронт отрисует компонент и без него. Также бывает, что для свойств на фронте зашиваются дефолтные значения. То есть, если в контракте не пришло свойство, отвечающее за цвет компонента, но для него на фронте зашито значение по умолчанию, то фронт отрисует его именно с этим значением. Если нужен другой цвет — то его уже можно прислать в контракте.
В нашем примере с контрактом экрана выше как раз необязательность свойства Paddings стало причиной слипшихся компонентов. Для них просто не заданы паддинги:
Если паддинги прописать для всех нужных компонентов в контракте, они корректно отобразятся на фронте:
Ну вот, так гораздо лучше 😎
Ключ description
Это параметр чисто для удобства чтения контракта компонента. Он описывает, для чего элемент JSON нужен, за что он отвечает:
В Альфе description обязателен для каждого параметра, чтобы избегать двусмысленностей и соблюдать однозначность. Однако в других продуктах может быть своя специфика.
Чтобы наша шпаргалка по контрактам была достаточно полной для базового погружения, осталось сказать пару слов про массивы.
Массивы в контрактах компонентов используются для отображения однородного списка возможных значений какого-либо свойства. В контрактах компонентов перечисление элементов массива будет идти в квадратных скобках после ключа “enum” или ключа “oneOf”.
Ключ Enum
Используется для перечня простых элементов. Например, через enum может быть описан перечень токенов типографики, который мы поддерживаем:
Ключ OneOf
Используется, если элементами массива являются объекты. Например, мы можем в отдельных файлах описать параметры пресетов для компонента кнопки:
Тогда вместо перечисления всех свойств кнопки в контракте экрана можно указать просто название пресета, который мы используем.
Главное — запомнить, что, если мы видим в коде “enum” или “oneOf”, значит перед нами массив однородных элементов, из которого в контракт экрана попадёт только какой-то один.
Резюмируем
И контракт экрана, и контракт компонента — это файлы в JSON формате.
Мы увидели, что JSON строится по определённым несложным правилам. Разобрались с тем, какие нам могут встретиться типы переменных, и изучили особенности объектов и массивов.
Контракты — это главный источник истины в BDUI подходе.
И теперь мы умеем правильно интерпретировать информацию из них. Это важно, потому что позволяет:
- получить ответы на вопросы без привлечения дизайнеров дизайн-системы и разработчиков;
- самостоятельно разобраться с возможностями и ограничениями компонентов и фреймворка в целом;
- отслеживать ошибки во время дизайн-ревью и понимать природу их возникновения (вспоминаем пример с отсутствием отступов между компонентами).
Также важно сказать, что особенности реализации BDUI в вашем продукте — не что-то высеченное в камне и неспособное меняться. Наоборот, BDUI хорош своей гибкостью, хотя изменения порой требуют времени. Теперь мы можем предлагать осознанные и масштабируемые доработки в фреймворк, общаясь с разработчиками на одном языке.
Ну и, наконец, умение работать с кодом в BDUI развивает вас профессионально. И точно делает привлекательнее как кандидата, особенно, если вы хотите попасть на работу в продукт, где BDUI уже используется.
Завершим статью практическими рекомендациями
№1. Запаситесь терпением. Изучение новой компетенции этого требует. Не переживайте, если после прочтения статьи у вас в голове пока не складывается чёткая картина того, что с этим всем делать. Возвращайтесь к ней, как к шпаргалке время от времени, когда будете сталкиваться с конкретными кейсами в работе. Постепенно пазл сложится.
Как команда дизайн-системы, в Альфе мы уделяем много времени адаптации наших дизайнеров к развитию BDUI. Пишем статьи для онбординга, проводим консультации, прожариваем макеты. И всё равно ребята приходят с вопросами. Это нормально.
Кроме того, часто и мы сами, чтобы найти ответы на эти вопросы, идём в репозиторий с контрактами и ищем их там. BDUI — живой организм, постоянно развивается и меняется. Выучить всё наизусть невозможно, но можно научиться работать с источниками истины.
№2. Не бойтесь, что не получится. Задавайте глупые вопросы. Разработчики, как правило, рады помочь.
В Альфе must-have практикой считается регулярное обсуждение промежуточных макетов дизайнером и разработчиком команды. Иногда бывает проще на этапе черновиков спросить у разработчика «а есть ли у нас свойство, которое позволит вот так сделать» и получить быстрый ответ, чем закапываться в документацию.
№3. Изучите разметку и синтаксис JSON. Это поможет читать контракты экранов и компонентов, которые являются в BDUI источниками истины.
Для продуктового дизайнера достаточно того, что описано в этой статье.
№4. Узнайте базовые особенности реализации BDUI именно в вашей компании. Как минимум, какие есть очевидные ограничения. Например, у вас может не быть возможности закрепить кнопку внизу экрана, или добавить анимацию контенту при скролле, или изменять динамически контент экрана в зависимости от действий пользователя. Здесь всё очень индивидуально, разработчики подскажут.
№5. Помните, что в BDUI внесение изменений в компоненты может занимать больше времени. Закладывайте это в сроки.
Иногда времени на то, чтобы сразу всё сделать по красоте, нет. В Альфе в таких случаях мы можем запустить фичу в том виде, в котором позволяет текущая реализация BDUI. И сразу начинаем работать над тем, чтобы через какое-то время выкатить обновление с целевой версией.
№6. Выстраивайте более качественный процесс дизайн-ревью экранов собранных на BDUI. В классическом подходе мы даём фидбек с перечнем правок фронт-разработчику, но в BDUI разработчик не влияет на внешний вид экрана. Возможно, лучшим вариантом будет созвониться с ним и обсудить отдельно каждый пункт фидбека, чтобы понять, как можно повлиять на ситуацию.
№7. Помогайте другим дизайнерам — фиксируйте то, что сами узнали. Пишите гайды, проводите воркшопы, обменивайтесь опытом, проводите дизайн-чеки друг для друга. Даже если вы сейчас единственный дизайнер, пишите гайды по BDUI в вашем продукте так, как будто дизайнеров много. В будущем это сильно поможет и им, и вам.
В Альфе именно так, из заметок дизайнеров по работе с BDUI в вебе, со временем сформировался полноценный набор спецификаций для каждого BDUI компонента и описания основных паттернов. Это сильно помогло, когда наши дизайнеры стали кросс-платформенными, и ребятам пришлось быстро разбираться со спецификой BDUI для веба.
№8. Попросите разработчиков собрать фронтовую витрину BDUI компонентов.
В Альфе такие витрины есть и для натива, и для веба. Они удобны тем, что можно быстро покрутить разные сочетания свойств компонентов, и посмотреть, получится ли собрать то, что нужно. Зачастую это помогает найти ответы гораздо быстрее, чем погружение в контракты.
№9. Дизайнерам дизайн-систем: задумайтесь над тем, чтобы поддерживать как-то описание особенностей BDUI в дизайн-системе.
В некоторых случаях в Альфе мы «обучаем» понимать BDUI контракт уже существующие в дизайн-системе компоненты. Для них мы спроектировали шаблон описания того, какие из свойств компонента поддерживаются в BDUI, а какие нет. И помещаем его в description компонента в фигме.
На этом всё. Поделитесь своим опытом погружения в BDUI в комментах и оставляйте пожалуйста обратную связь. Спасибо.
Регистрируйтесь на онлайн-трансляцию Alfa Design Meetup #3. Вячеслав будет выступать там с темой «У вас BDUI: как с этим жить».
Автор:
Вячеслав Соколов, дизайнер цифровых продуктов в Альфа-Банке