Дизайн-система как газон: читаем тропы, которые вытоптали команды

В любом парке есть место, где асфальтовая дорожка делает аккуратный прямой угол, а рядом по траве идёт вытоптанная диагональ. Её никто не планировал. Никто не принимал решение «ходим здесь». Просто в какой-то день один человек спешил, за ним второй, и через месяц земля стала голой.
Ландшафтные архитекторы называют такое тропами желаний, и я не знаю лучшей метафоры для дизайн-системы, которая «протухла». Мы привыкли думать, что система устаревает, потому что её забросили. Мне кажется точнее другое: она устаревает, потому что по ней ходят. Просто не там, где проложено.
Газон не умирает за один день
Про «полгода» из названия честно: это не закон природы, а образ. Срок у каждой команды свой. Важен механизм. Сначала одна команда делает кнопку на два пикселя выше, потому что в её экране иначе не сходится. Потом другая берёт цвет «примерно как в системе, но темнее». Третья копирует компонент к себе, чтобы не ждать релиза.
Каждый случай разумен. Вместе они дают дрейф: исключений становится столько, что норма уже не отличается от нарушения.
Тропа — это голосование ногами
Первая реакция руководителя системы: поставить забор. Запретить отклонения, ввести согласования, назначить строгого ревьюера. Это работает ровно до дедлайна, после которого заборы просто обходят, и уже с чувством вины. А виноватая команда скрывает исключения, и система перестаёт знать, что происходит у неё в собственном парке.
Я предлагаю читать тропы как данные. Не все они означают одно и то же:
| Что видно | Что это значит | Что делать |
|---|---|---|
| Одно и то же исключение у трёх команд | В системе нет нужного варианта | Превратить в задачу бэклога и заасфальтировать |
| Компонент копируют к себе и правят | API неудобен или в нём есть баг | Чинить компонент, а не ругать копировщиков |
| Разовое отклонение под конкретный экран | Особый случай | Разрешить с датой пересмотра, но не нормализовать |
| Свои значения вместо токенов | Токена нет, не знают о нём или не доверяют | Выяснить, какой из трёх вариантов, прежде чем что-то лечить |
Последняя строка самая неприятная. Adoption, то есть принятие системы командами, это не «установили пакет». Это ещё и знание, что нужное есть, и уверенность, что оно сработает. Установленный пакет рядом с россыпью жёстких значений в стилях выглядит как асфальт посреди вытоптанного поля.
Садовник нужен, и ему нужно время
У газона должен быть садовник. Не «все понемногу», а человек или маленькая команда, у которой поддержка системы записана в планы, а не делается в остаток между продуктовыми задачами. Триаж обращений, релизы, разбор исключений должны быть в roadmap, иначе их съест первая же срочная фича.
Первое, что я бы завёл, это журнал исключений. Скучный, короткий, обязательный:
исключение: кнопка с иконкой слева, высота 44 вместо 40
кто: команда «Заказы» (вымышленный пример)
почему: у нас длинные подписи, иначе переносятся
пересмотр: начало следующего квартала
Причина, владелец, дата. Если исключение повторилось у второй команды, оно перестаёт быть исключением и становится задачей. Если срок вышел, его либо продлевают осознанно, либо убирают. Так тропа получает имя, а не растёт молча.
Асфальт тоже должен уметь заканчиваться
Вторая половина проблемы с обратной стороны: система не только позволяет тропам расти, но и сама оставляет за собой мусор. Устаревший компонент, который «пусть пока будет». Страница документации про вариант, которого уже нет в коде.
Поэтому компоненты и токены я считаю публичным API со всеми вытекающими:
- версии по semver, ломающие изменения только в major;
- пометка устаревшего и предупреждение прямо в типах, чтобы редактор ругался за вас;
- codemod, который переписывает старое использование автоматически;
- запрет нового использования в CI;
- удаление в следующем major.
Ритм тоже важен. Мелкие релизы раз в месяц-два, ломающие изменения пачкой и заранее объявленные, changelog к каждой версии. Команда должна знать, когда будет больно, и успеть подготовиться.
Пусть карту рисует машина
Любой ручной процесс синхронизации устаревает быстрее, чем вы успеваете его описать. Если у вас две «истины», макеты и код, плюс документация, которую обновляют руками, расхождение — вопрос времени. Поэтому всё, что можно сверять, надо сверять автоматически:
- линтер ловит жёстко заданные значения там, где должен быть токен;
- проверка паритета токенов между макетами и кодом;
- visual regression на компонентах;
- сборка падает, если у компонента нет актуального примера и описания свойств.
Документацию я бы вписал в definition of done: без примера, таблицы свойств и заметок о доступности компонент не готов. Какая сторона главная, макеты или код, спорят до сих пор. Всё чаще выбирают нейтральный контракт токенов и синхронизацию в одну сторону. Мне эта идея нравится: исчезает вопрос, кто прав.
И последнее про метрики. Среднее по больнице скрывает именно тех, кто идёт по траве. Смотрите импорты, версии и жёсткие значения в разрезе команд, а раз в квартал собирайте небольшую группу, человек четыре-восемь, и спокойно проходите по карте вытоптанного.
В ближайший понедельник не затевайте реформу. Откройте любой продукт и найдите три места, где команда обошла систему. Для каждого ответьте на вопрос, чего ей не хватило: варианта, удобства или доверия. Это и есть ваш настоящий бэклог. Про то, когда системе вообще пора появляться, я писал раньше, а здесь важнее другое: проложить дорожки там, где люди уже ходят.