
Большинство дизайн-систем терпят неудачу по одной простой причине: они необязательны.
Если вы хотите стабильной консистентности UI, нужно перестать относиться к дизайн-системе как к рекомендации и начать относиться к ней как к контракту.
В этом посте — практичный, воспроизводимый способ добиться этого. Он основан на моём реальном продакшен-сетапе, но паттерн достаточно универсален для любого кодбейза, любого фреймворка и любого coding-агента.
(Можно схитрить: просто скормите агенту эту статью и попросите внедрить систему :D)
Что такое дизайн-система?
Дизайн-система — это общий контракт на то, как строится и ведёт себя ваш UI.
Как минимум, она обычно включает:
- Дизайн-токены (цвет, отступы, типографика, радиус, тень)
- Переиспользуемые компоненты (кнопки, формы, карточки, модалки и т.д.)
- Паттерны взаимодействия (лейаут, навигация, состояния ошибок, progressive disclosure)
- Правила использования (что делать, чего избегать и что обязательно)
Без этого контракта каждая новая поверхность дрейфует. С ним — продукт остаётся консистентным, даже когда код быстро генерируется агентами.
Почему одной документации недостаточно
Документация необходима, но недостаточна.
Агент может прочитать ваши стилевые правила — и всё равно нагенерить сырые spacing-классы.
Агент может иметь ваши стандарты типографики — и всё равно захардкодить text-[44px] чтобы попасть в макет.
Агент может пропустить form wrapper и напрямую импортировать примитивы.
Это происходит не потому, что агент вредничает. Это происходит потому, что система не делает правильный путь — самым лёгким путём.
Чтобы это исправить, нужен enforcement на каждом этапе работы.
Модель enforcement'а
Детерминированный workflow дизайн-системы состоит из пяти слоёв:
- Каноническая документация — единый источник правды для визуального языка и правил взаимодействия.
- Роутинг агента — skill или инструкция, заставляющая агента обращаться к документации.
- Локальные lint-правила — кастомные проверки, падающие на некомплаентном коде.
- Pre-commit хуки — проверки staged-файлов, запускающиеся автоматически перед коммитом.
- CI gates — проверки при мёрже, блокирующие дрейф от попадания в main.
Суть не в каком-то одном слое. Суть в перекрытии. Если один слой что-то пропустит, другой поймает.
1) Каноническая документация: пишите правила, которые можно проверить автоматически
Большинство стайлгайдов слишком размыты для линтинга.
«Используй консистентные отступы» — нельзя залинтить.
«Используй семантические spacing-токены (xxs, xs, s, m, l) и никогда — сырые числовые утилиты (mt-3, px-4, gap-2)» — можно залинтить.
Разделите документацию на три документа с чёткими задачами:
- Design rules — жёсткие DO/NEVER-политики.
- Visual language — маппинг токенов, стилевые примитивы компонентов, контракты типографики и цвета.
- Interaction patterns — контракты лейаута и поведения для флоу и поверхностей.
Добавьте явный раздел «Machine Enforcement», в котором перечислены команды и поведение гейтов. Если чего-то нет в этом разделе — оно не является контрактным обязательством.
2) Роутинг агента: заставьте агента сначала сверяться с нужным источником
Если вы используете coding-агентов, добавьте выделенный design-system/SKILL.md.
Его задача проста:
- Направлять задачи, связанные с дизайном, к нужной документации.
- Предотвращать ad-hoc стилевые решения.
- Держать визуальные гайдлайны централизованными.
Это превращает «не забудь проверить дизайн-систему» в детерминированное поведение.
Полезная ментальная модель: агент должен вести себя как pipeline компилятора, а не как собеседник в чате. Входные данные проходят через политики, затем происходит реализация.
3) Кастомные lint-правила: закодируйте дизайн-контракт в коде
Готовые линтеры не смогут полностью проверить вашу дизайн-систему. Нужны кастомные правила под ваши конкретные стандарты.
Типичные высокоценные проверки:
- Spacing token check — запрет сырых spacing-утилит; обязательные семантические токены.
- Color token check — запрет сырых hex/rgb/hsl литералов и произвольных color-утилит.
- Token contract check — проверка, что CSS-переменные, Tailwind-токены и примитивы компонентов синхронизированы.
- Typography constant check — обязательные общие heading-константы, запрет сырых heading-утилит.
- Shared wrapper check — принудительное использование form wrappers вместо сырых примитивов.
Держите правила строгими, но практичными. Добавьте явные маркеры исключений для редких edge cases и требуйте указание причины при использовании.
// pseudo-rule
if (classToken.matches(/^(mt|mb|px|py)-\d+$/)) {
fail("Use semantic spacing token (e.g. mt-s), not numeric utility");
}
Конкретная реализация менее важна, чем принцип: если нарушение можно обнаружить, оно должно блокироваться автоматически.
4) Pre-commit хук: быстрый фейл на staged-файлах
Pre-commit — это место, где compliance становится привычкой.
Запускайте staged-линт дизайн-системы одной командой в хуке. Держите единую точку входа, чтобы агенты не плутали между несколькими перекрывающимися командами.
npm run lint:design-system:staged
Эта команда должна оркестрировать все ваши дизайн-проверки (spacing, цвета, token contract, формы, типографика) для staged-файлов.
Почему именно staged?
- Быстрая обратная связь.
- Сфокусированный сигнал.
- Низкое трение для итеративной работы.
Когда агенты получают немедленные, конкретные ошибки до коммита — фиксы происходят, пока контекст ещё свеж.
5) CI gate: тот же контракт, но удалённо
Локальные проверки необходимы, но не авторитетны.
CI должен запускать тот же контракт дизайн-системы и фейлить PR при внесении дрейфа. Иначе compliance зависит от того, запускал ли каждый локальный environment те же проверки.
Рекомендуемый паттерн:
- Запускать lint дизайн-системы для изменённых файлов на PR'ах.
- Опционально — полный sweep по репо по расписанию или перед крупными релизными ветками.
- Трактовать failure как блокирующий.
Это разница между «мы поощряем консистентность дизайна» и «мы гарантируем консистентность дизайна».
Scope — это всё
Частая причина провала enforcement-проектов: команды пытаются залинтить всё сразу.
Начните с осознанного scope'а.
Для многих продуктов это означает: сначала enforce для основного приложения, а админки и legacy-маркетинговые страницы — отложить до отдельного редизайна.
Задокументируйте scope чётко — и в доках, и в lint-правилах. Неоднозначный scope создаёт бесконечные false positives и «усталость от политик».
Обработка исключений без хаоса
Исключения будут. Цель — контролируемые исключения.
Простая политика:
- Исключения требуют inline-маркера.
- Маркер должен содержать краткую причину.
- Исключения ревьюятся как технический долг.
- Периодический аудит и удаление устаревших исключений.
Это сохраняет систему строгой, не делая её хрупкой.
Как это выглядит в повседневной работе
Типичный workflow:
- Задача просит агента построить новую UI-поверхность.
- Агент проходит через skill дизайн-системы и документацию.
- Агент пишет код с использованием общих констант/токенов/wrappers.
- Pre-commit запускает staged design lint.
- Любое нарушение фейлится немедленно с конкретным сообщением.
- Агент исправляет нарушения.
- CI перезапускает тот же контракт на PR.
- Мёрж проходит только когда дизайн-проверки зелёные.
С этого момента консистентность дизайна больше не зависит от памяти, вкуса или дисциплины.
Как внедрить это в вашем репо
Можно раскатать, если держать scope узким:
- Консолидируйте дизайн-доки в чёткие политики + референсы токенов.
- Добавьте skill/инструкцию-роутер дизайн-системы для агента.
- Реализуйте 2–3 высокоценных кастомных lint-правила (spacing, цвета, wrappers).
- Создайте одну команду-оркестратор (
lint:design-system). - Добавьте staged-вариант и подключите к pre-commit.
- Добавьте CI gate с тем же командным контрактом.
- Добавьте явную политику scope и исключений.
- Расширяйте правила инкрементально по мере стабилизации нарушений.
Не стремитесь к совершенству. Стремитесь к детерминизму.
Типичные ошибки
Остерегайтесь:
- Несколько конкурирующих lint-точек входа, запутывающих workflow агента.
- Доки, ссылающиеся на удалённые файлы или устаревшие команды.
- Правила строгие, но не actionable.
- Scope, включающий немигрированные поверхности слишком рано.
- Отсутствие политики исключений → тихие ad-hoc обходы.
Лечение всегда одно: централизовать, упростить, сделать enforcement явным.
Итог
Если вы хотите, чтобы агент использовал вашу дизайн-систему — не просите вежливо.
Закодируйте дизайн-систему как контракт.
Направляйте каждую UI-задачу через неё.
Запускайте локальные и удалённые гейты, которые фейлятся детерминированно.
Держите доки, линтеры, хуки и CI в синхронизации.
Как только вы это сделаете, консистентность дизайна перестанет быть намерением и станет автоматикой.