Сейчас я старший продуктовый дизайнер с восьмилетним опытом, но для того, чтобы понять, как функционирую сложные системы и процессы, мне понадобилось пройти через множество задач и преобразований. Одной из таких задач стала собственная, «ванильная» дизайн-система, которая была разработана не для работы тысяч клиентов, а для удобной навигации строителей, инженеров и внутренних сотрудников строительных компаний. Как часто это бывает — идея была здравая. Её реализация тоже не подкачала, но сейчас, глядя на весь пройденный путь, я чётко вижу моменты, которые я бы отработал иначе.
Кому будет полезно?
В первую очередь дизайнерам, работающим с нестандартными интерфейсами. Нестандартный интерфейс в данном случае тот, который содержит неочевдиные механизмы — 3D пространство, объёмные массивы данных, связи «многие-ко-многим». Ещё дизайнерам, лидам и овнерам, которые размышляют над тем, нужна ли им собственная дизайн-система вообще. Ну и наконец тем, кто уже работает с дизайн-системой и размышляет над её масштабированием.
Контекст
В 2020 году один из крупнейших застройщиков Санкт-Петербурга имел свой научно-технический центр, отвечающий за цифровизацию процесса строительства. На тот момент уже широко был развит BIM — система 3D моделирования строительных объектов, хранившая внутри моделей плотный слой информации о будущем здании. Компании требовался веб-дизайнер, так как весь сервис проектировался в вебе. Эту позицию я и занял, начав постепенно разбираться в сути. Сервис на тот момент не существовал как что-то целое и единое: это был набор различных инструментов, нацеленных в первую очередь на пачку прозрачных отчётов.
Первым крупным цифровым инструментом был модуль безопасности. Инженеры обходили строительные площадки, фиксировали нарушения на бумаге, а затем переносили информацию в BIM-модель на рабочем компьютере. Позже процесс частично перевели на планшеты, что позволило отмечать нарушения непосредственно на объекте.
В течение следующих месяцев к модулю безопасности добавились документооборот, пожарная безопасность, передача квартир покупателям, исполнительная документация, технический надзор и другие сервисы. Всего в продуктовом контуре появилось более 15 модулей.
Команда на старте состояла из пяти разработчиков, двух frontend- и трёх backend-инженеров, а также группы специалистов строительного профиля. Проектирование интерфейсов в основном выполняли сами инженеры. Их основной задачей было перенести сложные строительные процессы в цифровую среду. Системное проектирование пользовательского интерфейса в этот процесс не входило.
Исходное состояние интерфейсов
Каждый модуль развивался как отдельный инструмент. Новая функция обычно проектировалась под конкретную задачу и сразу передавалась в разработку.
UI-kit отсутствовал. Разработчики использовали базовые элементы frontend-фреймворков, дополняя их локальными компонентами. Большая часть решений создавалась заново.
В интерфейсах накопились типовые проблемы:
- одинаковые действия выглядели и работали по-разному;
- использовались несвязанные между собой иконки;
- не было единой типографической шкалы;
- интервалы и размеры элементов задавались локально;
- цветовые решения не учитывали требования контрастности;
- отсутствовали единые правила для таблиц, форм, модальных окон и состояний;
- иерархия данных зависела от конкретного модуля;
- компоненты разрабатывались под один сценарий и редко переиспользовались.
Например, формирование отчёта, экспорт отчёта и фиксация нарушения могли быть реализованы тремя разными способами. В одном модуле использовалась кнопка, в другом иконка, в третьем действие находилось внутри выпадающего меню.
Для пользователей это увеличивало время освоения новых модулей. Для разработки это означало поддержку большого количества одноразовых решений.
Каждая новая задача порождала новый интерфейс, новую frontend-реализацию и новый слой legacy.
Постановка задачи
Изначально задача не формулировалась как создание дизайн-системы.
Необходимо было объединить разрозненные сервисы научно-технического центра в единый продукт. Для этого требовалось одновременно систематизировать несколько уровней:
- бренд;
- ролевую модель;
- интерфейсную систему;
- принципы интернационализации;
- единую точку входа;
- правила масштабирования продукта.
Дизайн-система стала инфраструктурной частью этой работы.
Её основные цели:
- Снизить количество локальных интерфейсных решений.
- Ускорить проектирование новых модулей.
- Сократить объём повторной frontend-разработки.
- Зафиксировать единые правила для desktop и tablet.
- Создать общий язык между внутренней командой, подрядчиками и разработкой.
- Обеспечить постепенную миграцию существующих продуктов без полной переработки legacy.
Build or adopt
На первом этапе мы рассматривали два варианта:
- использовать готовую UI-библиотеку;
- создать собственную дизайн-систему.
Основным аргументом в пользу собственной системы была BIM-модель.
Стандартное отображение BIM-модели
Продукт содержал большое количество сценариев, связанных с 3D-пространством: навигацию, выбор элементов, фильтрацию, работу со слоями, фиксацию нарушений, назначение статусов и групповые операции.
Мы предположили, что готовая библиотека не сможет покрыть эти сценарии без существенных ограничений.
Дополнительными факторами были:
- одновременная поддержка desktop и tablet;
- работа инженеров непосредственно на строительных площадках;
- высокая плотность данных;
- необходимость крупных интерактивных зон для планшета;
- нестандартные режимы взаимодействия с BIM-viewer.
На основе этих вводных было принято решение создать собственную систему.
При проектировании foundations я анализировал Ant Design, Gravity и Fluent. Из этих систем были взяты устойчивые принципы построения компонентов, состояний, типографики и иерархии. Визуальные и технические параметры адаптировались под Contrust.
Ретроспективно это решение оказалось частично ошибочным. Специфические сценарии действительно требовали собственной систематизации, но большинство базовых компонентов можно было построить поверх существующей библиотеки.
Архитектура дизайн-системы
Система состояла из нескольких уровней:
- Foundations.
- Tokens.
- Primitive components.
- Composite components.
- Product patterns.
- Domain patterns.
- Product modules.
Такое разделение позволяло отделить общие правила интерфейса от специфики строительных сценариев.
Foundations
В foundations вошли:
- цветовая система;
- типографика;
- spacing;
- radius;
- borders;
- surface;
- elevation;
- grid;
- iconography;
- размеры интерактивных элементов;
- правила для desktop и tablet.
Для типографики использовался PT Root UI. Гарнитура хорошо работала с кириллицей, выдерживала высокую плотность интерфейса и могла свободно использоваться в продукте.
Типографическая шкала строилась с коэффициентом 1,25. Для малых размеров применялся увеличенный интерлиньяж в 140%. По мере роста размера текста относительный интерлиньяж уменьшался пропорционально.
Цветовая модель разделялась на три уровня:
- primitive colors;
- semantic colors;
- component tokens.
Например:
Blue / 600
→ Action / Primary
→ Button / Background / Primary
Это позволяло менять визуальные параметры без ручной переработки каждого компонента.
Tokens
Для токенов использовался собственный префикс. Через них описывались:
- цвета;
- размеры;
- отступы;
- радиусы;
- границы;
- типографика;
- свойства surface;
- отдельные component-level значения.
Токены использовались как общий источник правил для Figma и фронта.
На раннем этапе часть значений существовала как вручную синхронизируемая система. После выхода Variables в Figma мы перевели активную часть UI-kit на переменные.
Миграция заняла около двух недель периодической работы нескольких дизайнеров.
Мы разделили макеты на три категории:
| Состояние | Решение |
| Активная работа | Перевести на Variables |
| В разработке | Перевести на Variables |
| Уже выпущенный legacy | Сверить с токенами, не перестраивать |
Полную миграцию старых макетов не проводили. Стоимость такой работы не соответствовала её практической ценности.
Компонентная архитектура
Компоненты строились атомарно с использованием nested components и component properties в Figma.
Основной принцип был следующим:
Если вложенный элемент мог независимо менять состояние, он оформлялся как отдельный компонент.
Например, поле ввода могло включать:
- label;
- input area;
- placeholder;
- entered value;
- leading icon;
- trailing action;
- helper text;
- validation message;
- error state.
Каждая часть, которая имела собственные варианты или состояния, проектировалась отдельно и затем вкладывалась в основной компонент.
Это позволяло управлять сложным компонентом из одной панели свойств, не разбирая его вручную.
Кнопки были представлены примерно в следующих параметрах:
- 5 размеров;
- несколько визуальных типов;
- 4 варианта сочетания текста и иконки;
- состояния default, hover, active, disabled, loading;
- tablet- и desktop-размерности;
- варианты для полноширинного и компактного размещения.
Кроме кнопок в систему вошли:
- inputs;
- dropdowns;
- selects;
- tooltips;
- avatars;
- badges;
- lists;
- tables;
- grids;
- popovers;
- modals;
- accordions;
- drawers;
- rails;
- quiz controls;
- status components;
- navigation controls.
При этом количество компонентов не рассматривалось как самостоятельная метрика зрелости системы.
Основным критерием была способность закрывать новые задачи существующими сущностями.
Компоненты и продуктовые паттерны
После запуска базовой библиотеки стало понятно, что консистентности на уровне компонентов недостаточно.
Одинаковые элементы могли использоваться в разных последовательностях, с разной логикой и разными состояниями. Поэтому поверх библиотеки компонентов был создан слой продуктовых паттернов.
В него вошли:
- сворачивание drawer в navigation rail;
- перевод BIM-модели в fullscreen;
- режимы модальных окон;
- фильтрация;
- аккордеоны;
- popover-сценарии;
- таблицы с bulk actions;
- режим выбора элементов модели;
- групповые действия;
- паттерны статусов;
- сценарии работы с планшетом.
BIM Multi Select
Одним из основных доменных паттернов стал выбор нескольких объектов внутри BIM-модели.
Сценарий состоял из четырёх шагов:
- Пользователь открывает модель в обычном режиме навигации.
- Включает режим выбора.
- Выбирает несколько элементов модели.
- Применяет действие ко всей группе.
После включения режима кнопка оставалась в активном состоянии. Пользователь мог выбрать 3, 6 или 10 объектов, после чего выполнить групповое действие.
К выбранным элементам могли применяться:
- изменение статуса;
- создание нарушения;
- назначение ответственного;
- добавление в проверку;
- фильтрация;
- включение в отчёт.
Для этого паттерна требовалось синхронизировать:
- состояние toolbar;
- состояние модели;
- визуальное выделение объектов;
- счётчик выбранных элементов;
- доступные действия;
- выход из режима;
- отмену выбора;
- конфликт с native controls viewer.
Этот сценарий был специфичен для продукта и действительно требовал собственной системы правил.
Контроль роста библиотеки
По мере развития продукта владельцы модулей регулярно предлагали новые элементы.
Одним из примеров была шахматка квартир. Изначально задача выглядела как запрос на новый сложный компонент.
После декомпозиции выяснилось, что интерфейс состоит из трёх уже существующих сущностей:
- grid;
- badge;
- status token.
Вместо разработки отдельного компонента мы собрали матрицу квартир из существующих badge-компонентов с заданной сеткой и статусами.
Новый системный компонент не потребовался.
Для принятия подобных решений использовались следующие критерии:
- Можно ли решить задачу существующим компонентом.
- Можно ли расширить существующий компонент новым variant.
- Повторяется ли сценарий в других модулях.
- Является ли решение локальным или системным.
- Требует ли оно отдельной документации.
- Будет ли компонент поддерживаться в Storybook.
- Насколько высока стоимость его дальнейшего развития.
Figma, Storybook и документация
UI-kit существовал в Figma и параллельно переносился в Storybook.
В Storybook фиксировались:
- компонент;
- его состояния;
- варианты;
- технические параметры;
- правила использования;
- ограничения;
- примеры.
Документация готовилась совместно с frontend-разработкой и техническим писателем.
Таким образом система включала:
- Figma UI-kit;
- tokens;
- Storybook;
- текстовую документацию;
- brandbook;
- правила contribution;
- changelog;
- governance.
Figma не рассматривалась как единственный источник дизайн-системы. Она была рабочим инструментом дизайнеров, но кодовая реализация и документация имели равный статус.
Работа с распределёнными командами
К моменту запуска UI-kit к проекту подключились внешние команды дизайна и frontend-разработки.
Из-за ограничений Figma, стоимости лицензий и последующих санкционных ограничений команды работали в разных окружениях.
Централизованное подключение всех дизайнеров к одной библиотеке было невозможно.
Для синхронизации использовался следующий процесс:
- головной UI-kit оставался у внутренней команды;
- первая страница файла была отведена под changelog;
- изменения сопровождались ссылками на конкретные компоненты;
- два раза в неделю внешние дизайнеры проверяли обновления;
- после синхронизации они оставляли отметку о просмотре;
- спорные изменения обсуждались отдельно;
- предложения по новым компонентам проходили через внутреннюю дизайн-команду.
Такой процесс был частично ручным, но обеспечивал управляемое распространение системы между независимыми командами.
Где система ломалась
Основные проблемы возникали не в компонентной архитектуре, а в организации работы.
У каждого модуля был владелец. Обычно это был специалист, хорошо знающий конкретный строительный процесс и связанные с ним юридические, финансовые или операционные риски.
В условиях срочного релиза владелец модуля мог напрямую обратиться к дизайнеру подрядчика и попросить добавить новый элемент.
Типовой сценарий выглядел так:
- Владельцу модуля требовалось срочное изменение.
- Он передавал задачу внешнему дизайнеру.
- Дизайнер создавал новый локальный компонент.
- Решение попадало в макет.
- Разработчик не находил компонент в UI-kit.
- В Storybook и документации его также не было.
Такие элементы существовали только внутри одного макета. Для них можно использовать термин orphan components.
Причинами были:
- сжатые сроки;
- распределённые команды;
- локальные договорённости;
- скрытые экспертные знания;
- отсутствие обязательного review;
- давление со стороны владельцев модулей.
Governance
Для контроля новых решений был введён обязательный review на уровне внутренней дизайн-команды.
Любой новый компонент или паттерн должен был пройти следующую проверку:
1. Можно ли использовать существующий компонент?
Если да, новая сущность не создавалась.
2. Можно ли расширить существующий компонент?
Если задача решалась новым variant или property, обновлялся текущий компонент.
3. Является ли сценарий повторяемым?
Если решение использовалось только в одном локальном сценарии, оно могло остаться product-specific pattern.
4. Нужна ли системная сущность?
Если решение было повторяемым и применимым в нескольких модулях, оно проходило design review.
После этого выполнялись:
- проектирование в Figma;
- согласование с frontend;
- реализация в Storybook;
- подготовка документации;
- обновление changelog;
- распространение по командам.
Governance уменьшил количество несогласованных элементов и зафиксировал единый процесс развития библиотеки.
Работа с BIM-viewer
Отдельной проблемой было взаимодействие собственной интерфейсной системы с controls, встроенными в BIM-viewer.
Viewer мог предоставлять собственные инструменты:
- навигацию;
- работу с камерой;
- выбор объектов;
- управление слоями;
- изоляцию элементов;
- скрытие объектов;
- измерения.
Contrust также содержал controls поверх модели:
- фильтрацию;
- переключение режимов;
- групповой выбор;
- назначение статусов;
- фиксацию нарушений;
- переход к сущности;
- работу с карточкой объекта.
В результате на одном экране существовали две системы управления.
Необходимо было определить:
- какие действия остаются внутри viewer;
- какие переносятся в интерфейс Contrust;
- какие native controls скрываются;
- какие действия перехватываются;
- какой режим считается приоритетным;
- как избежать конфликта selection states;
- как пользователь выходит из модального режима модели.
Часть решений пересматривалась несколько раз. Основная сложность заключалась не в визуальном оформлении кнопок, а в согласовании двух interaction models.
Автоматизация иконок
Для иконок использовался собственный icon font.
Процесс был частично автоматизирован:
- Иконка создавалась в Figma.
- Экспортировалась через внутренний плагин.
- Добавлялась в шрифт.
- Обновление отправлялось в Git.
- Frontend-команда получала актуальную версию.
После обновления ветки новая иконка становилась доступна в продукте без ручной передачи отдельных SVG-файлов.
Результат
В результате была создана полноценная дизайн-система, которая включала:
- UI-kit;
- foundations;
- tokens;
- component library;
- product patterns;
- BIM patterns;
- Storybook;
- документацию;
- changelog;
- contribution rules;
- brandbook;
- governance.
Первые три модуля вышли в production с единым визуальным и интерфейсным языком.
Они использовали:
- общую точку входа;
- единые компоненты;
- общую типографику;
- стандартные состояния;
- одинаковые принципы работы с данными;
- согласованную логику desktop и tablet.
На этой основе начали разрабатываться следующие модули.
В продуктовом контуре использовалось более 15 сервисов. Дизайн-система позволила перевести их развитие из набора локальных интерфейсных решений в управляемую модель.
Основной качественный результат заключался в том, что новые задачи больше не начинались с пустого файла у дизайнера и новой реализации у frontend-разработчика.
Команды получили общий набор решений, общий процесс согласования и общий источник правил.
Выводы
Сначала стандартизировать частое, потом специфичное
Большая предметная область не означает, что ей нужна полностью уникальная библиотека компонентов. Большинство базовых задач Contrust закрывались стандартными UI-паттернами. Кастомизация имела наибольшую ценность там, где начиналась специфика продукта: BIM, строительные статусы, проверки и работа инженеров на площадке.
Рост библиотеки сам по себе ничего не доказывает
Новый компонент стоит добавлять только тогда, когда существующие компоненты, их свойства и композиции не закрывают задачу. Чем больше сценариев удаётся собрать из уже существующих элементов, тем устойчивее система и дешевле её поддержка.
Governance нужно проектировать вместе с компонентами
Даже хорошо организованный UI Kit быстро теряет консистентность, если продуктовые команды могут обходить его при срочных задачах. Changelog, design review, contribution flow и критерии появления новых компонентов оказались не менее важны, чем сами компоненты.
Миграция должна иметь практическую ценность
Не каждое изменение дизайн-системы требует обновления всего legacy. Активные макеты имеет смысл поддерживать в актуальном состоянии, а уже выпущенные интерфейсы достаточно проверять на совместимость и обновлять тогда, когда они снова попадают в работу.
Что не получилось
Основной ошибкой было решение полностью разрабатывать базовую UI-библиотеку самостоятельно.
Команда вручную проектировала и кодировала:
- buttons;
- dropdowns;
- tooltips;
- inputs;
- popovers;
- базовые состояния;
- стандартные controls.
При этом большая часть этих компонентов не имела специфики строительного продукта.
Изначальная логика выглядела так:
Сложный BIM-продукт
→ нестандартные сценарии
→ полностью собственная дизайн-система
На практике корректная модель была другой:
Готовая UI-библиотека
- ▸ собственные tokens и theme
- ▸ строительные product patterns
- ▸ BIM interaction layer
После того как внутри компании закрепилось представление о полностью собственной дизайн-системе, отказаться от этой модели стало сложно. Собственная разработка воспринималась как технологическое преимущество и стала частью внутренней коммуникации проекта.
В результате часть ресурсов была потрачена на повторную реализацию стандартных компонентов.
Что я сделал бы иначе
Если бы аналогичная система создавалась сейчас, я бы разделил её на два уровня.
Стандартный уровень
Основа на базе зрелой библиотеки, например Ant Design:
- buttons;
- inputs;
- dropdowns;
- tooltips;
- modals;
- tables;
- popovers;
- standard states;
- accessibility behavior.
Доменный уровень
Собственные решения для Contrust:
- BIM selection mode;
- model filtering;
- construction statuses;
- apartment matrix;
- inspection flows;
- object violations;
- desktop-tablet adaptation;
- interaction between viewer and product UI.
Такой подход сократил бы стоимость разработки и поддержки базовых компонентов.
Основные ресурсы можно было бы направить на сценарии, в которых продукт действительно отличался от стандартных enterprise-систем.
Главный вывод проекта состоит в следующем:
Сложность предметной области не требует полной уникальности базового интерфейса. В Contrust специфичными были строительные процессы, BIM-сценарии и работа инженеров на площадке. Кнопки, dropdown и tooltip могли оставаться стандартными.
Связаться со мной
Если есть желание обсудить этот кейс, другие кейсы или пообщаться по иным вопросам в сфере продуктового дизайна — пишите мне в телеграм или на почту. Подробнее обо мне и моей работе можно узнать на моём сайте. Сейчас я в поисках продуктовой команды, в которой смогу развивать продукт и быть полезным игроком. Пишите, буду рад пообщаться!