Кто я и почему пишу

Привет, Хабр! Меня по-прежнему зовут Сергей Орлов, я разработчик в Dodo Engineering и лидер дизайн-системы Android в приложении Пиццы. Это моя прощальная статья в Додо – про то, как мы заводили дизайн-систему, где наступили себе на ногу и что из этого вышло.

Сразу предупрежу, чего в статье не будет. Это не гайд по токенизации проекта и не правила написания компонентов – такого добра в сети хватает. Это рассказ про грабли: какие мы нашли, как их обходили и что бы я сделал иначе.

До Додо я строил дизайн-системы в Мегафоне и Магните – причем с двух сторон: в одной компании пилил компоненты, в другой пользовался ими как клиент из фичевой команды. Опыт с обеих сторон баррикады оказался полезнее, чем я думал: половина проблем в ДС возникает ровно потому, что тот, кто делает компонент, не представляет, как с ним потом жить.

Поэтому на собеседовании в Додо я спросил, есть ли у них дизайн-система. Мне ответили, что нет.

Как выяснилось позже, ответ был не совсем точный. Но об этом чуть ниже.

Как мы дошли до жизни такой

Я пришел в Додо, когда готовился редизайн всего приложения. Честно говоря, он был нужен – просто посмотрите.

Меню приложения: слева до редизайна, справа сейчас

Если вам есть что сказать про дизайн приложения – велком в комментарии или в телеграм-канал наших дизайнеров designdodo. Троллей там тоже любят, так что не стесняйтесь.

Немного цифр для масштаба. В приложении Пиццы около 60 полноэкранных экранов, плюс порядка 40 диалогов и шторок. Считать элементы на всех этих layout’ах я не стал: боюсь, надоест, либо закончатся токены.

Перерисовать все это нужно было быстро, итерационно и так, чтобы к концу пути приложение оставалось однородным, а не превратилось в лоскутное одеяло из экранов разных эпох и локальных компонентов. Тут на сцену и выходит дизайн-система.

С чем мы столкнулись и что будет в этой статье

  1. Почему общий модуль компонентов – это еще не дизайн-система. Разбор на примере соседней платформы, где модуль живет с 2020 года и спокойно содержит пять реализаций одного контрола.

  2. Как отличить компонент дизайн-системы от компонента фичи. Мы не отличили – и получили две кнопки, которые подменяли друг друга по всему приложению.

  3. Паспорта компонентов. Спека, где дизайн и разработка договариваются до того, как написана первая строка кода. Что в ней есть и почему это документ для разработчика, а не бюрократия дизайна.

  4. Как раздать разработку компонентов всем командам. Когда на платформу приходится один человек с ДС и десять с фичами, других вариантов нет. Процесс, схема, что сломалось при внедрении.

  5. Как объяснить бизнесу, что ускорение сначала тормозит. Работает не объяснение, а цена: компонент надо сделать дешевле в спринте.

  6. Скриншот-тесты на компоненты. Что покрыли и почему для ДС они дешевле, чем кажется.

  7. Генерация компонентов нейронкой и пять слоев защиты вокруг нее. Что скармливаем на вход, что она стабильно делает плохо, и почему без предыдущих шести пунктов это не работает.

Дальше будет код, схемы и признания в собственных косяках. Если такое заходит – я про это регулярно пишу в своем телеграм-канале https://t.me/orlovsdev

Почему просто вынести компоненты в общий модуль недостаточно

Первой моей задачей в Додо была фича «курьер на карте». Я открыл макет, открыл проект и понял, что собирать экран не из чего.

Точнее так: собирать было из чего, и в этом заключалась проблема. Чтобы понять масштаб, достаточно посчитать, сколько в проекте было кнопок. Один класс-наследник MaterialButton, две кастомные View с «Button» в имени, пять самостоятельных Compose-кнопок в разных модулях, 28 XML-стилей кнопок и 14 layout-файлов, где кнопка собрана руками из кликабельного контейнера и TextView.

Такая копипаста заводится не от лени, а от отсутствия дешевой альтернативы. Когда общего компонента нет, у разработчика два пути: собрать кнопку заново с нуля или скопировать ту, что уже работает в соседней фиче другой команды. Второй быстрее и надежнее – поэтому чаще предпочтительнее.

Так получилось, например, с экраном фидбека – кнопка, которая лежала в двух модулях побайтово одинаковая, а один блок разметки кнопки повторялся в семи файлах пяти модулей, отличаясь только id и text.

<Button
    android:id="@+id/buy_more_add_to_cart"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="@string/buy_more_add_to_cart"
    style="@style/PrimaryButton"
    />

Цена такого решения заметна не сразу. Любое изменение кнопки приходится вносить в семи местах, предварительно найдя все ее копии – и ты никогда не уверен, что нашел все.

Второй путь – не копировать, а брать чужой компонент напрямую – выглядел правильнее, но выходил дороже. Пятнадцать кастомных View стояли на экранах чужих модулей. Рекордсмен – ExpandableFoodValueInfoIconView (раскрывающаяся плашка с составом продукта) из модуля order, он попал в восемь чужих экранов.

Берешь компонент соседней команды, через две недели владельцы правят его под свою задачу – и у тебя едет верстка на экране, о котором они не знали. Формально мы переиспользовали код. Фактически подписывались на чужие релизы.

Ни один из двух путей не ведет к системе. Копипаста позволяет команде не зависеть от чужого кода, но плодит копии одного и того же. Переиспользование чужого компонента убирает дублирование, но связывает команды общей реализацией. Иначе говоря: копипаста дает изоляцию без переиспользования, чужой компонент – переиспользование без изоляции. Дизайн-система нужна ровно затем, чтобы появился третий вариант: компонент, у которого есть владелец и контракт.

Онбординг стоит дороже, чем кажется

Compose меняется быстро и порой радикально – это все мы знаем. Из-за этого практики написания UI на проекте живут в головах, а не в коде.

Представьте нового человека на проекте, где есть Compose без ДС-обертки, а местами еще и View. Чтобы написать первый экран, ему нужно выяснить, как у вас принято собирать компоненты, найти похожие в коде, прочитать их реализацию и понять, какая из трех найденных версий правильная. Это не день и не два.

Задайте себе этот вопрос, когда будете думать про дизайн-систему. Именно про систему, а не просто про набор компонентов – почему второе тоже плохо, расскажу ниже.

У нас к этому добавлялось еще и то, что верстали мы на View. С каждым новым наймом было видно, как экспертиза в нем падает: люди приходили из проектов на Compose, для них наш основной инструмент был легаси. Мы не деградировали – просто нанимали в технологию, которая для рынка уже прошлое.

Модуль есть, системы нет

Копипаста, размазанная по пяти модулям, зависимость от чужих компонентов, неделя на экран, долгий онбординг – рано или поздно разработчики приносят это на синк и просят завести дизайн-систему. Но бизнес не всегда может дать добро сразу: нет людей, есть другой приоритет, причин много.

И тут возникает соблазн: сделать свой техпак с компонентами и заставить всех их использовать. Задайте себе вопрос – это решит проблему или замаскирует ее?

У коллег с iOS такой модуль был: живой, с 2020 года, много тысяч строк кода. При этом внутри него уживались пять реализаций одного сегмент-контрола, а карточка продукта существовала в трех вариантах. То же самое, что у нас на Android, только сложенное в один модуль вместо разбросанного по проекту.

Проблема не в компоненте. Он может быть идеальным, написанным по всем лекалам.

Дизайн-система – это не только код. Это еще и договоренность между людьми.

Если вы договорились внутри своей команды, но не сказали дизайнерам и не построили с ними общий процесс – вы обрекаете себя копировать с мелкими изменениями собственные же эталонные компоненты.

Как отличить компонент ДС от компонента фичи

У нас эта договоренность появилась. Дизайн и разработка сели вместе, дизайн-систему завели официально, первый компонент приехал в проект.

А через 24 дня мы сами же положили рядом с ним второй, который дизайн-системой не был.

Первый компонент

Первым нашим компонентом логично стал самый используемый элемент любого приложения – кнопка. Та самая оранжевая кнопка, которую вы можете видеть по всему нашему приложению.

@Composable
fun DComposeButton(
    onClick: () -> Unit,
    text: String,
    buttonSize: ButtonSizesData,
    colors: ButtonColorsData,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    isProgress: Boolean = false,
    imageData: ImageData? = null,
)

Сразу оговорюсь: восемь параметров подряд – это нарушение нашего же правила. Компонент должен принимать data class с параметрами, чтобы расширяться через него, а не через правку сигнатуры. На старте мы этого не сделали – и за два года кнопка обросла параметрами до неприличия, пока мы не завезли DButtonState. Правило, кстати, родилось именно отсюда.

Три состояния, четыре размера, пять цветовых стилей. Архитектура сразу двухслойная: композабл плюс AbstractComposeView поверх – чтобы кнопку можно было ставить в существующие XML-лейауты и не переписывать экран целиком ради одной кнопки. Позже от этого подхода мы отказались, и сейчас так устроена только эта кнопка. В тот же день появился сторибук для нее, про него расскажу ниже.

Через 24 дня

Мы совершили ошибку, которая стоила нам дорого и до сих пор живет в проекте. Мы добавили ProductButton.

Я лично боролся с этим, но моих аргументов в тот момент оказалось мало. Не всегда один в поле воин, даже если дизайн-системой скроен.

Написали мы его не как обертку над DButton, а как самостоятельный компонент, который вызывает Button из Material3 напрямую:

val buttonSize = DButtonSizes.large.copy(
    contentPadding = PaddingValues(horizontal = 20.dp, vertical = 8.dp)
)

Button( // material3, не DButton
    onClick = onClick,
    shape = RoundedCornerShape(percent = 50),
    colors = colors.getButtonColors(),
) {
    when (price) {
        is ProductPrice.SimplePrice -> { /* иконка + цена */ }
        is ProductPrice.PersonalPrice -> { /* старая цена дугой + новая */ }
        is ProductPrice.CoinsPrice -> { /* валюта + курсив + додокоины */ }
        is ProductPrice.EditedSimplePrice -> { /* заголовок + цена мельче */ }
        is ProductPrice.EditedCoinsPrice -> { /* заголовок + валюта и коины */ }
    }
}

От ДС он взял ровно два объекта-токена – размер и цвета, причем размер тут же пропатчил через .copy().

И это было понятное решение. Часто время выигрывает у аргументов. В итоге с этой болью должны были столкнуться все, чтобы понять неверный путь этого компонента. ProductButton умел то, чего DButton не умел: зачеркнуть старую цену дугой, показать две строки, смешать типографику внутри одной подписи, вывести цену в рублях и додокоинах сразу. Подзаголовок в DButton появился только через девять месяцев.

Так у нас образовались две кнопки: одна из дизайн-системы, вторая из фичи, и вторая умела больше.

Чем это кончилось

Дальше произошло ровно то, что должно было. В макет просится DButton, но нужного состояния у него нет – а у ProductButton есть. Берем ProductButton. В компонент цены начинают доливать «просто текст»: состояние с произвольным заголовком, состояние с подписью под ценой.

Кончилось это вот таким кодом в конструкторе комбо:

if (screenState.selectedProduct != null) {
    ProductButton(
        modifier = Modifier.width(250.dp),
        productPrice = ProductPrice.PriceWithComment(/* ... */),
    )
} else {
    DButton(
        modifier = Modifier.size(width = 250.dp, height = 52.dp),
    )
}

Один слот на экране. Две разные кнопки. Выбор через if.

Правило, которое из этого выросло

Фича зависит от ДС, а не наоборот.

Если компоненту фичи не хватает состояния из дизайн-системы – это заявка на доработку компонента ДС, а не повод написать свой. Проверка простая: посмотрите, где лежит код и на что он ссылается. Компонент ДС не знает ничего о фиче. Компонент фичи может брать из ДС что угодно.

Проблема в том, что различить это надо до того, как написан код. Через восемь месяцев, когда компонент уже в проде и оброс состояниями, «просто переписать» стоит дороже, чем оставить как есть, – что мы и продемонстрировали.

И еще одна проблема, которая для меня оказалась важнее. Правило само по себе не работает, пока оно живет в голове одного человека. Нужен был механизм, который делает его общим и предъявляемым – не «мне кажется», а «смотрите, вот здесь не сходится».

Так у нас появились паспорта.

Паспорта компонентов и сторибук

Паспорт – это спецификация компонента, о которой дизайн и разработка договариваются до того, как написана первая строка кода. Название прижилось само.

Живет он в Figma, отдельной страницей на компонент, имея секции для дизайнеров и разработчиков. Внутри секции разработчиков живут подсекции для Android и iOS.

Зачем паспорт разработчику

Он дает готовый прообраз API, который удобно скормить в том числе нейронке, об этом ниже.

До паспортов все это выяснялось по ходу: сверстал, отдал на приемку, получил замечания, переделал. После – требования к компоненту известны до начала разработки.

Заполняет паспорт дизайнер, но принимаем мы вместе: на пятничном синке лиды ДС смотрят его и предлагают правки. Мы, как разработчики, приносим гайдлайны платформы, дизайнеры приносят замысел.

Помните спор про ProductButton, где у меня был правильный аргумент и не было инструмента? Мы просто положили рядом два паспорта – обычной кнопки и продуктовой – и увидели, что по составу это один и тот же компонент. Спорить стало не о чем: паспорт превращает мнение в аргумент.

Правила написания компонентов

Паспорт отвечает на вопрос «что делаем», правила разработки – на вопрос «как».

Правила лежат у нас во внутренней вики. Там зафиксировано, как должен быть устроен компонент:

  • только токены, никаких захардкоженных цветов и размеров;

  • состояние типизировано через sealed interface, а не через набор булевых флагов;

  • дефолты вынесены в отдельный объект;

  • компонент stateless и ничего не знает про заказ, корзину и тоглы;

  • опциональный контент передается слотом, а не тремя параметрами.

Антипример здесь – реальный код нашего DButton. Правило написано по следам собственной ошибки.

Сторибук: место, где компонент становится видимым

Паспорт живет в Figma, компонент – в коде, и между ними нужно место, где можно потрогать результат. У нас это сторибук: экран в дебажной сборке, где каждый компонент лежит отдельным пунктом и все его параметры переключаются прямо в UI.

Дизайнеру он нужен, чтобы не искать компонент по экранам приложения – приемка проходит именно там. Разработчику – чтобы увидеть, что уже сделано и в каком объеме.

Экран в сторибуке у нас обязательный шаг, а не опция: пока компонента нет в песочнице, следующий разработчик о нем не узнает и напишет свой.

Дизайнеры первое время забывали заполнять паспорта, разработчики не рвались делать компоненты вместо фичевых задач. Механизм появился, а привычки не было. Ни то ни другое документом не лечится – как чинили, дальше.

Нас двое на две платформы

Механизм появился, а рук не прибавилось. И я знал это с самого начала, так как опыт имелся. Дизайн-системой занимались два человека – я на Android и коллега на iOS. На двоих приходилось около 20 фичевых разработчиков на двух платформах, редизайн всего приложения и библиотека компонентов, которую надо было довести до кода целиком.

Вариант «мы вдвоем все напишем, а команды будут пользоваться» отпал сразу. Даже если бы мы успели – это ровно тот bus factor, из-за которого дизайн-системы и умирают: два человека уходят, и система остается без хозяина.

Поэтому мы сели вдвоем и накидали процесс, в котором компонент делает тот, кому он понадобился.

Логика простая. Когда в фиче появляется компонент дизайн-системы, разработчик проверяет паспорт: существует ли он вообще и описаны ли в нем нужные состояния. Если чего-то не хватает, додумывать поведение на месте нельзя – вопрос уходит в общий канал к владельцам ДС и ответственному дизайнеру.

Когда паспорт на месте, решение зависит от того, что уже есть в коде и сколько времени в спринте:

Ситуация

Кто делает

Что происходит

Компонент реализован, состояний хватает

Разработчик фичи

Просто берет и использует

Компонента нет или не хватает состояний, времени нет

Владельцы ДС

Задача передается им: актуализируют документацию, дописывают компонент и подключают его в фичу. Не «сделай как-нибудь у себя», а именно передача

Компонента нет, но время есть

Разработчик фичи

Приходит к владельцу платформы, показывает фичу и свое решение – кодом или хотя бы мыслями. Владелец валидирует

Если зафиналить общее решение не получилось, договариваетесь, как реализовать по месту. Важно, что это остается осознанным исключением – и осознанным техническим долгом, а не самодеятельностью.

Хвост процесса общий для всех веток: разработка по паспорту и требованиям из вики, обязательное добавление в сторибук, потом два ревью – владельца ДС со стороны разработки и дизайнера. Замечаний нет – раскатываешь фичу.

В итоге мы получили не только дополнительные руки. Компоненты перестали быть чьей-то личной территорией, а разработчики получили задачи вне фичевой рутины. Плюс каждый, кто прошел процесс хоть раз, дальше сам замечает в макете компонент ДС.

Фича важнее компонента

Первое время разработчики делали компонент не целиком. Прилетел макет, в нем нужны два состояния из семи – два и написали. Формально компонент в дизайн-системе есть, фактически он дырявый, и следующий человек снова упирается в «нужного состояния нет».

Это логичное поведение, а не саботаж: у разработчика в спринте фича, а не дизайн-система.

И тут мы уперлись в то, во что упирается любая ДС. Продуктовые задачи всегда важнее, потому что они приносят деньги сейчас. Компонент целиком стоил 3–5 сторипоинтов – это заметный кусок спринта, и его старались срезать до тех состояний, без которых фича не поедет.

Объяснить бизнесу, почему штука, которая должна ускорять разработку, сначала ее тормозит, – задача со звездочкой. Но суть любых переговоров – это найти компромисс. С моей стороны родилась идея сделать компонент дешевле. Как? Пишу ниже.

Как мы сделали компонент дешевле

Компонент стоил 3–5 сторипоинтов, и это была честная оценка. Написать восемь состояний, покрыть превью, добавить в сторибук, пройти два ревью – работы там действительно на несколько дней.

Значит, снижать нужно было не оценку, а объем ручной работы.

Прежде чем генерировать – научились проверять

Скриншот-тесты на ДС-компоненты мы завезли недавно, и поначалу это выглядело как обычная гигиена: ну покрыли, ну молодцы.

Механизм – Compose Preview Screenshot Testing: тест не описывает верстку сам, а переиспользует @Preview-функции из файла компонента.

class DButtonComposeScreenshotTests {

    @PreviewTest
    @Preview("Light")
    @Preview(
        "Dark",
        uiMode = Configuration.UI_MODE_NIGHT_YES or Configuration.UI_MODE_TYPE_NORMAL
    )
    @Composable
    @VisibleForTesting
    private fun Preview1() {
        DButtonPreview()
    }
}

Для дизайн-системы это почти бесплатное покрытие. Превью у компонентов и так обязательны по нашим же правилам, тесты гоняются на хосте без эмулятора, эталоны лежат рядом с кодом. Сейчас в ДС-модуле 23 файла тестов и 115 эталонных картинок.

Честно про цену: плагин до сих пор в статусе экспериментальной альфы, и мы это понимали, когда заводили.

Зачем эта сетка понадобилась на самом деле, стало понятно через полтора месяца.

А что, если бойлерплейт просто сгенерировать?

Я взял шторки – DBottomSheet и DContentBottomSheet – и попробовал сгенерировать их нейронкой.

Смысл был не в том, чтобы «ИИ написал за меня компонент». Смысл в том, что в компоненте дизайн-системы огромная доля работы – это бойлерплейт: разложить состояния, развесить токены, собрать Defaults, написать превью на каждый вариант. Все это выводится из паспорта механически.

Эксперимент получился. Дальше я рассказал о нем на общем синке команд – и подход разошелся по командам сам.

Нейронке нельзя оставлять выбор

Главный принцип: снять все вопросы до начала генерации, чтобы модели нечего было додумывать.

  • Макет из Figma через MCP, фреймами.

  • Паспорт компонента – состояния, размеры, стили, правила поведения.

  • Правила и ограничения из нашей вики – как писать компоненты на нашем проекте.

  • Эталонный компонент как образец стиля.

  • Все это упаковано в скилл, чтобы не собирать контекст руками каждый раз.

Отдельная работа шла на стороне дизайна. Мы договорились с дизайнером, отвечающим за ДС, что паспорта адаптируются под это: никаких скрытых компонентов, никаких неявных дизайнерских хуков, состояния проработаны детально – так, чтобы вопросов не было ни у человека, ни у машины. Неоднозначные места сначала были, мы их вместе вычистили.

Побочный эффект оказался приятным: паспорта от этого стали лучше и для людей тоже.

Что нейронка делает плохо

Переизобретает то, что уже есть. Внутри нового компонента пишет свою кнопку вместо готовой, хардкодит значение вместо токена – при том, что токены лежат в контексте.

Иногда лепит булевы флаги вместо типизированного состояния. Бывало нечасто, но бывало – то есть ровно та ошибка, из-за которой мы намучились с ProductButton, только теперь ее предлагает машина.

Превью не пишет вообще, пока не ткнешь носом. Для Compose это база, любой разработчик их пишет по умолчанию – а модель их пропускает, и ее приходится отдельно вести по всем состояниям из паспорта. И это не косметика: без полного набора превью не работают скриншот-тесты, то есть молча ломается покрытие.

Выедает токены на больших компонентах. ДС – не единственная тема на проекте, контекст приходится делить.

Требует перепроверки. Модель регулярно продолжает следовать своим представлениям о прекрасном, даже когда в контексте лежат ваши правила.

Ошибаться можно. Дорого ошибаться – нельзя

Именно поэтому генерация работает не сама по себе, а внутри всего, что мы построили до нее:

  1. Паспорт – что именно должно получиться.

  2. Правила и эталонный компонент – как это писать у нас.

  3. Скриншот-тесты – регрессия ловится автоматически, а не глазами на ревью.

  4. Сторибук – дизайнер принимает компонент руками.

  5. Ревью – нейронкой и людьми. Состязательное ревью моделью работает неплохо: ошибается, но базу собирает хорошо. Поверх этого код смотрит разработчик, и я как лид отдельно прохожусь по компонентам. Здесь важно, что цена ошибки уже не та: если фича в проде, значит критических багов по ней нет, а поправить код компонента – не проблема. Все обложено тестами, и если новый компонент что-то сломает в фиче, мы это отловим.

Собственно, в этом и смысл всех пяти слоев. Не в том, чтобы нейронка не ошибалась, – она будет. А в том, чтобы ошибка стоила дешево и находилась до пользователя.

Нейронка убирает бойлерплейт. Знание, как это должно быть устроено, живет в разработчике.

Кстати, тут хорошо видно, как меняется работа программиста. Программировать все еще нужно уметь – иначе вы просто не заметите подставу. Но большая часть времени теперь уходит не на написание, а на проверку за машиной.

Выгода для бизнеса

Компонент стал стоить 2 сторипоинта стабильно вместо прежних 3–5.

Команды перестали срезать компоненты. Раньше в спринте выбирали между фичей и компонентом, теперь компонент помещается рядом с фичей – и его берут целиком.

Я не объяснял бизнесу, почему ускорение сначала тормозит. Я сделал компонент дешевле, и он объяснился сам.

Дальше стало возможным то, о чем раньше не заходила речь: мы поставили целью довести до кода все компоненты, уже готовые в Figma, и распределили их по командам – по тому, чьи модули и контуры они затрагивают и у кого какая загрузка.

Где мы сейчас

Цифры на август 2026 года:

  • 34 компонента в дизайн-системе, 31 из них готов на Android – 91%

  • 34 экрана компонентов в сторибуке плюс 5 экранов основ: типографика, цвета, градиенты, анимации, вибро

  • 23 файла скриншот-тестов и 115 эталонных картинок в ДС-модуле

  • ДС-модуль импортируют 479 kt-файлов. На старте их было 29

Дашборд появился не сразу и оказался нужнее, чем ожидалось. Там видно готовность по обеим платформам и тренд по времени – без него вопрос «а это уже сделано?» решался поиском по коду и опросом коллег.

На скрине видно разрыв: Android 91%, iOS 53%. Дело не в том, что коллеги медленнее – им прилетело жидкое стекло, и это переписывание половины UI под новую систему оформления, а не «доделать компонент». Мы в это время спокойно шли по своему бэклогу. По графику тренда, кстати, хорошо видно, что кривая iOS не встала, а продолжает расти – просто с другим стартом.

Что можно сделать лучше

Дизайн-система растет вместе с проектом, и работы в ней всегда хватает. Что напрашивается дальше:

Структурированное версионирование. Сейчас версия живет в паспорте, со стороны разработки процесс еще не до конца обточен. Это связано с тем, что у нас еще молодая ДС.

Дашборд пошире. Хочется видеть покрытие глубже.

Больше скиллов и обвязки вокруг генерации, чтобы завести компонент стоило еще дешевле.

Это не список долгов, а нормальное состояние живой системы. Если бы делать было нечего – значит либо продукт не развивается, либо ДС от него отстала.

Вместо заключения

Дизайн-система остается. Не как код в репозитории, а как процесс, который работает без меня: есть паспорта, есть правила, есть люди в каждой команде, которые проходили этот путь и знают, как делать компонент.

Собственно, ради этого мы и раздавали разработку компонентов всем командам. Тогда bus factor был аргументом из презентации. Теперь он проверился на мне – и это, пожалуй, лучший результат из всех, что перечислены выше.

А я продолжаю писать про разработку в своем телеграм-канале – заходите, там про то, что происходит дальше: https://t.me/orlovsdev

Если у вас было по-другому – расскажите в комментариях. Особенно интересно, как это устроено у тех, кто заводил дизайн-систему в проекте с большим легаси.