Меня зовут Анастасия Кабалкина, я Head of design в VK Tech. В этой статье расскажу, как мы синхронизировали треть нашей дизайн-системы за счет автоматической генерации дизайн-токенов и компонентов.
Продукты и особенности разработки
Наше направление занимается разработкой финансовых и аналитических b2b-продуктов — VK Tax Compliance, VK GRC, VK Data Symphony, VK Process Mining и т.д. Помимо сопровождения решений, уже выпущенных на рынок, мы ежегодно реализуем порядка 10 продуктовых инициатив, и наш продуктовый портфель постоянно (и очень быстро) растет и развивается.
У такого быстрого роста есть обратная сторона — контролировать качество интерфейсов и обеспечивать единство UX/UI-паттернов становится сложно и одновременно очень важно.
«Рассинхрон» дизайна и фронта
Несколько лет назад мы, как и большинство команд продуктовой разработки, столкнулись с проблемой «рассинхрона» дизайна и фронта.
В нашей дизайн‑системе периодически появляются новые компоненты, уже существующие дорабатываются и развиваются, некоторые устаревают — и далеко не все эти изменения со 100%‑ной точностью переносятся на frontend (по очень разным причинам).
В какой‑то момент «рассинхрон» стал критическим — почти каждый компонент на frontend‑е хоть и немного, но расходился с дизайном.
Очевидно, что даже самые мелкие несоответствия в своей совокупности очень сильно искажают общую картинку. Где‑то используется не тот цвет, где‑то не тот отступ, не то скругление, размер — и в итоге мы в реальности получаем вообще не такой интерфейс, как на макете.
Наши попытки синхронизировать дизайн и frontend «традиционными» методами не увенчались успехом. Нам не удалось ни встроить в процесс разработки отдельный этап дизайн‑ревью, ни вручную сверить все компоненты, ни выделить специальное время в спринтах под эту активность — у нас всегда находились задачи приоритетнее.
Но и смириться с «рассинхроном» тоже нельзя, потому что от него в конечном итоге страдают все — и дизайнеры, и разработчики, и аналитики, и presale‑менеджеры, и тестировщики, и, что важнее всего, пользователи и бизнес.
Идея автогенерации стилей и компонентов из Figma-файла
Что делать, если работу выполнять надо, а времени на неё нет? Единственный вариант — автоматизировать.
Конечно, автоматизация тоже требует ресурсов, но в основном на этапе её внедрения, дальше она очень сильно экономит время‑ и трудозатраты и повышает общую эффективность процессов.
Мы решили автоматизировать перенос стилей и компонентов из дизайна в код и стали выяснять, существуют ли уже инструменты, которые позволяют это сделать, например, плагины для Figma или отдельные продукты.
Ничего подходящего мы не нашли, но присмотревшись к API Figma поняли, что в целом из него можно получить необходимый объем информации и попробовать сгенерировать стили и компоненты самостоятельно.
Общая схема процесса выглядит так:
Мы забираем данные напрямую из Figma‑файла через API.
Пропускаем их через самописный генератор кода (далее — Figma‑генератор).
На выходе получаем дизайн‑токены стилей в форматах css, json, ts (но можно и в любом другом), иконки в svg и код для компонентов на react (javascript).
Сгенерированные компоненты автоматически помещаются в storybook.
Источником кодогенерации является Figma‑файл, поэтому в нем обязательно должны быть отражены все параметры стилей и компонентов.
Для этого мы придумали специальный формат организации стилей и параметризации компонентов в Figma, который подходит для генерации и при этом не конфликтует с общепринятыми подходами к оформлению дизайн‑систем.
Оформление Figma-файла для автогенерации стилей
Текстовые стили, цвета и эффекты оформляются стандартным способом через Local styles (Text styles, Color styles, Effect styles) и генерируются как есть без дополнительных настроек.
Для генерации стилей, которые нельзя оформить через Local styles (в нашем случае это border, borderRadius, spacing и iconSize*), создаются специальные компоненты. Каждому компоненту присваивается название стиля и те параметры, за которые этот стиль отвечает.
Например, для генерации стиля обводки создается компонент с названием стиля (допустим, default, fieldBorder, imageBorder или любым другим на усмотрение дизайнера и frontend‑разработчика) и присвоенными параметрами Stroke color и Stroke width. Если стилей обводки несколько, то для каждого стиля создается отдельный компонент.
*Код для генерации стилей был написан до появления Variables. Сейчас у нас в планах доработать в этой части Figma‑генератор, чтобы генерировать стили и из Local styles, и из Variables.
Оформление Figma-файла для автогенерации компонентов
Генерация компонентов — задача более сложная и комплексная, так как компоненты обладают множеством характеристик, которые нужно корректно передать и обработать с помощью Figma‑генератора.
Вот несколько примеров таких характеристик:
наличие вариантов, отличающихся друг от друга комбинациями параметров,
наличие псевдосостояний (псевдоклассов), определяющих стили компонента в зависимости от состояния, в котором компонент находится (hover, focus, active, checked),
компоненты могут содержать в себе другие компоненты (например, компонент icon внутри кнопки),
компоненты могут конфигурироваться (например, icon внутри кнопки может отображаться или нет, а также может располагаться справа и/или слева),
компоненты могут содержать текст (например, label кнопки, чекбокса или радиобаттона), а также фигуру или кривую (например, галочка внутри чекбокса или круг внутри радиобаттона).
Чтобы компонент сгенерировался корректно, Figma‑генератор должен получить из Figma‑файла всю вышеперечисленную информацию и на её основании сгенерировать код компонента на React (JavaScript). Для этого мы разработали несложную методику верстки и параметризации компонентов в Figma на основе функций Auto layout и Properties.
Все наши компоненты верстаются с помощью функции Auto layout:
параметрами Horizontal gap between items, Horizontal и Vertical padding мы устанавливаем падинги и внутренние отступы,
параметрами Min width, Max width, Min height и Max height определяем пределы ширины и высоты компонента,
устанавливаем возможность «обрезать» не помещающийся текст параметром Truncate text,
устанавливаем допустимое количество строк в текстовом контейнере параметром Max lines.
Кроме того, мы также передаем на frontend тип поведения компонента с помощью параметров Horizontal и Vertical resizing (будет ли размер компонента зависеть от его контента (hug) или компонент будет занимать всё отведенное для него место (fill)).
Примеры оформления свойств
Для оформления свойств с множественными значениями (например, свойство size со значениями xs, s, m, l) мы используем функцию Variant property. Таким же способом задаются свойства, принимающие значения true/false, например, disabled, isNegative, isLoading и т. п.
Псевдосостояния (псевдоклассы) тоже задаются через Variant property, принимают значения true/false и дополнительно в названии этих состояний ставится двоеточие, чтобы Figma‑генератор смог отличить эти свойства от других (например,:hover,:focus,:active).
Булевы свойства мы оформляем стандартно с помощью функции Boolean (например, свойства showIconLeft, showFirstButton и т. п.), а для того, чтобы вставить компонент в другой компонент, областям вставки задаём параметр Instance swap property.
Если в компоненте присутствует контейнер с текстом, то такому контейнеру присваивается параметр Text с названием Children, чтобы на стороне frontend‑а была возможность «прокидывать» в компонент любой текст.
Достижения и ограничения автогенерации компонентов
Меньше чем за год мы научились генерировать 18 компонентов — и генерация каждого была своего рода вызовом.
Тем не менее нам удалось:
передать на frontend все основные параметры компонентов,
сгенерировать полноценные компоненты с оптимальным кодом, написанным так же грамотно, как если бы его писал квалифицированный разработчик,
сгенерировать компоненты с возможностью подключения к ним сторонних библиотек (например, мы самостоятельно генерируем компонент title, но компонент tooltip, появляющийся при наведении курсора на иконку «i», — это компонент AntDesign, который подключается автоматически).
У генерации есть и ограничения. Например, не все компоненты могут быть сгенерированы, главным образом потому, что это просто нецелесообразно — затраты на написание кода для генератора будут слишком большими и никогда себя не окупят (взять протестированный компонент select с уже продуманной логикой из открытой библиотеки несравнимо проще, чем с нуля написать генератор для этого компонента).
Также нам пока не удалось передать из Figma параметры анимации и придумать, как генерировать компоненты, принимающие в себя неограниченное количество других компонентов.
И, наверное, самое важное ограничение — Figma‑генератор получает данные через API, на который мы не можем влиять, соответственно, изменения в API или ограничение доступа к нему могут привести к необходимости доработки генератора или полному отказу от генерации компонентов таким способом. Да и кто знает, что будет в следующем обновлении Figma в Dev Mode?:)
Что мы в итоге получили
Несмотря на то, что сгенерировать всю дизайн‑систему нам не удалось, мы получили полностью генерируемую библиотеку стилей и набор автоматически генерируемых компонентов, которые составляют около 30% от всех компонентов нашей дизайн‑системы.
Что это значит для нас?
Это значит, что мы на 100% синхронизировали треть дизайн‑системы, а поскольку синхронизация выполняется автоматически, мы больше не должны тратить ресурсы на дизайн‑ревью хотя бы в этой части.
Генерируемые компоненты мы можем дорабатывать и дообогащать вариантами, а затем за считанные минуты доставлять их на frontend.
Мы можем стилизовать интерфейсы (менять цвета, шрифты, скругления и т. п.) буквально на лету.
У нас есть основа для дальнейших экспериментов, потому что Figma‑генератор можно совершенствовать и дальше.
Но самое важное, у нас (и теперь, надеюсь, и у вас) есть уверенность в том, что дизайнеры и frontend‑разработчики, работая и развиваясь вместе, способны решать самые оригинальные задачи!
Эта статья была посвящена особенностям дизайнерской части процесса, подробности кодогенерации будут в другой статье, которую мы уже очень ждем!
Благодарности
Спасибо команде за интересный внутренний проект, за смелость и поддержку, за неповторимый опыт и за помощь в подготовке этой статьи!
Если у вас есть идеи и предложения, то пишите их в комментариях :)