Всем привет, меня зовут Ростислав, я занимаю должность Front Lead в компании ДомКлик. Хочу поделиться с вами опытом создания Front Core команды и сразу ответить на следующие вопросы:


  • Необходима ли такая команда в компании?

После года существования команды Front Core, у всех сложилось понимание, что в больших компаниях это необходимо, а в стартапах — не обязательно.


  • Выгодно ли внедрять такую команду?

Безусловно. Изначально было сложно измерить и спрогнозировать выгоду от её создания, все расчеты, P&L были на словах, в цифрах — только примерные предположения. Спустя год мы можем посчитать сэкономленное время, профиты, и все расчеты говорят о том, что это было не зря.


  • На долгую перспективу ли эта команда?

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


  • Чем эта команда занимается?

Основное направление — дизайн система, но по ходу её разработки у нас появилось еще много интересных задач.


Предыстория


Создание Front Core команды началось с потребности разработать дизайн систему и библиотеку компонентов с последующей поддержкой и развитием, а также внедрить стандарты для frontend — разработки.


У нас в компании немало продуктовых команд, в каждой по несколько продуктов, состоящих из одного или нескольких веб-клиентов, которые могут содержать в себе виджеты и компоненты. Все веб-клиенты собираются в огромную экосистему ДомКлик, и, естественно, возникает вопрос о единообразии дизайна и UX-поведения всех элементов на страницах, чтобы клиент, переходя из продукта в продукт, понимал, что он в одной системе. И еще стоит вопрос об избыточных трудозатратах при разработке новой или доработке старой функциональности.


За всю историю ДомКлик было много попыток собрать библиотеку компонентов для их переиспользования во всех командах. Сначала пытались это делать в лояльном режиме: выделяли из своих проектов компоненты, которые можно переиспользовать, в отдельный репо и публиковали в npm-репозиторий. Затем компания энтузиастов решила собрать базу лучших компонентов в один проект со storybook, с единообразным API, и, по возможности, её поддерживать и дополнять. Но все эти попытки были тщетны до создания выделенной команды Web Core, у которой есть свои цели, обязанности и компетенции.


Дизайн-система и UI-KIT


Какие цели мы хотели достичь при создании дизайн системы:


  • увеличить скорость разработки продуктов;
  • повысить качество продуктов;
  • помочь разработке сконцентрироваться на создании бизнес логики;
  • увеличить лояльность аудитории за счет привычки работы с интерфейсом (UX);
  • а также иметь возможность трансформировать дизайн всей экосистемы, обновив лишь компоненты у себя в продукте.

Наша дизайн система будет состоять из таких элементов:


  • Гайдлайны и руководство по стилю — сетка, типографика, цвета, брейкпоинты.
  • UI-KIT — набор элементов пользовательского интерфейса для дизайнеров, основанный на гайдлайнах.
  • Шаблоны (паттерны) — композиция элементов UI-KIT для описания типового интерфейса.
  • Библиотека компонентов — кодовая база для использования в проектах. Включает в себя сами компоненты, документацию к ним, историю изменений, примеры использования с рекомендациями и правилами применения.

Дизайн


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


Основа всей дизайн системы — гайдлайны.



На основе гайдлайнов строятся базовые элементы. А на основе базовых элементов строятся более сложные элементы.



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


Разработка


А теперь перейдём к проектированию. Библиотеку компонентов мы разрабатываем на React — стандарте ДомКлик. Будем использовать Typescript для статической типизации, что помогает удобно использовать наши компоненты. Почему нельзя взять готовую библиотеку компонентов и просто интегрировать в нее нашу дизайн-систему? Во-первых, это тяжеловесные библиотеки, которые повлияют на производительность ваших продуктов. Во-вторых, вам постоянно будет не хватать их функциональности и придется их постоянно дорабатывать.


Перед началом разработки мы задали себе несколько задач:


Версионирование


Мы будем итеративно разрабатывать наши компоненты, улучшать их, добавлять новую функциональность. Вероятно, у нас будет меняться дизайн. Работаем мы по SemVer, т.е. фиксы и улучшения производительности мы выпускаем в патч-версии; добавления нового API и возможностей — в минор-версии; смена API для работы с компонентом, дизайна и его поведения — в мажор-версии.


Есть несколько способов поставки библиотеки компонентов конечному потребителю — продуктовым разработчикам.



Самый популярный вариант: один пакет UI-KIT, который ставишь целиком в проект и в дальнейшем обновляешь его при появлении новой версии. В этом случае должен безукоризненно работать tree shaking, иначе при сборке проекта мы получим даже те зависимости, которые не используем.


Достоинства:


  • Консистентное обновление всех компонентов разом, при котором не нарушается целостность UX в проекте. При патч- и минор-релизах со спокойной душой обновляем UI-KIT, если мы доверяем Web Core-команде.

Недостатки:


  • При мажорном обновлении версии UI-KIT разработчику необходимо потратить немало времени, чтобы проверить все сценарии использования компонентов на своем проекте, а также поддержать новое API использования. Затраченное время при мажорном обновлении можно рассчитать по формуле кол-во используемых компонентов * кол-во мест использования и если вы хотите получить новое обновление, в котором может появиться нужный вам компонент.
  • Потребителям придется заложить немало времени на обновление.


Второй вариант — каждый компонент UI-KIT как отдельный пакет. В этом случае каждый отдельно взятый компонент версионируется по SemVer.


Достоинства:


  • При появлении мажорных версий компонентов потребитель может обновлять итеративно.
  • После выхода нового компонента нет необходимости обновлять весь UI-KIT в проекте.

Недостатки:


  • Если потребителю нужно обновить все компоненты в рамках мажорной версии, то придется обновлять их по отдельности. Но в этом случае нам помогает полезная команда ncu --filter /@ui-kit/ -mu && npm i, где @ui-kit — scope библиотеки компонентов.

Мы выбрали второй вариант, потому что это менее болезненный путь для наших продуктов. В дальнейшем мы планируем выпустить один npm-пакет, который включает в себя все пакеты для тех команд, которым не страшно обновлять всё и сразу.


Мы будем работать в монорепозитории, потому что одни компоненты переиспользуют другие компоненты. Как мы будем управлять версионированием? Мы решили сравнить два наиболее подходящих инструмента для данной задачи: Lerna и RushJS.


Если смотреть на статистику, то Rush — наименее популярная библиотека. Так почему же мы выбрали её? Lerna была очень непредсказуемой и магической, нигде не было нормально описано, как она работает. Процесс релиза был недетерминирован. В Rush это сделано более системно: благодаря change-файлам ты всегда видишь, что поедет в релиз, и библиотека автоматически генерирует читабельные changelog, на основе которых бампит версии так, как тебе нужно. Также Rush работает с Git как надо. В целом эта библиотека показалась более зрелым инструментом, поэтому мы выбрали её.


Вот как мы работаем с Rush:



Сборка


Для сборки наших компонентов в формате ESM и ESNext с поддержкой tree-shaking мы используем Rollup, и ожидаем релиза Webpack 5, в котором нам обещают отличную поддержку этой функциональности. Чтобы у нас во всех пакетах была идентичная сборка и мы могли бы ее поддерживать и улучшать, мы можем везде ссылаться на один файл с конфигурацией. Но мы пошли дальше: создали библиотеку, которая этим занимается. Она гибкая, масштабируемая, и её можно использовать в других проектах для своих нужд. В ней уже соблюдены некоторые стандарты нашей компании: browserlist со списком поддерживаемых браузеров, сборка стилей, оптимизации для сборки библиотек и многое другое. Наши компоненты можно использовать в SSR-приложениях, при этом мы расширили поддержку старых версий NodeJS, собирая наши пакеты еще и в CommonJS-формате.


Стили


В наших компонентах мы используем CSS-модули и Sass как препроцессор.


О чем стараемся не забывать при этом подходе:


Версионирование стилей. Так как мы выбрали путь поставки компонентов по отдельности, а не целой библиотеки компонентов, потребитель может обновить только один пакет, не обновляя другие. В этом случае могут возникнуть конфликты между стилями разных версий компонентов. Поэтому при сборке пакетов в настройках для css-modules прописываем generateScopedName:'[local]-${projectManifest.version}', где projectManifest — файл package.json. Так у нас решаются все возможные конфликты.


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


Вы можете сказать, что для этих целей отлично подойдет CSS in JS. Не буду спорить, возможно, мы к этому придем.


Иконки


Многие задаются вопросом, каким способом предоставлять SVG-иконки. Изначально мы попробовали выгружать их на CDN по отдельности, но в этом случае получали перерисовку контента и много потоков скачивания. При использовании спрайта потребитель получает огромную (и тяжеловесную) портянку иконок, из которых он может использовать только несколько. Поэтому мы решили предоставлять React-компонентами, которые содержат в себе инлайново SVG-иконки. При сборке релиза запускается скрипт, который перегоняет SVG-файлы в IconComponent, заменяя все свойства fill на currentColor и применяя SVG-oптимизацию, поэтому нашим иконкам легко изменить цвет, задав его родителю.


Кроссбраузерность


Если вы поддерживаете старые версии браузеров и у вас десятки продуктов, вы тоже можете озадачиться такой проблемой, как полифилы. Их вы можете встретить везде: в используемой open-source библиотеке, в пакете, разработанном коллегой из другой команды, и, конечно же, в библиотеке компонентов. В итоге получается, что есть много веб-клиентов, собирающихся с полифилами для стабильной работы во всех браузерах.



Некрасиво, верно? Поэтому мы создали сервис полифилов, который не только позволит убрать их из приложений, но и в зависимости от сегмента браузеров отдавать набор тех полифилов, которые необходимы для стабильной работы приложения.



В зависимости от заголовка user-agent сервис отдает тот или иной набор полифилов. Мы выделили три набора для трех сегментов браузеров.



Размеры наборов составляют непосредственно:



В итоге мы получаем:


  • Уменьшение размера пакетов в продуктах в современных браузерах (наша целевая аудитория).
  • При входе в один из продуктов в браузере клиента кешируется пакет с полифилами, и при переходе из одного нашего продукта в другой мы улучшаем производительность и экономим трафик клиента.

Внедрение


Чтобы ваша библиотека компонентов удовлетворяла все потребности потребителей, нужно учесть следующие моменты:


  • Понятное API взаимодействия с компонентами с хорошей документацией.
  • Отсутствие избыточности. Мы все знаем open source-библиотеки, которые устанавливаем ради одного или нескольких сценариев использования, а вместе с этим получаем тонну ненужного кода. Поэтому мы стараемся создавать отдельно компоненты с базовой функциональностью, и на их основе отдельно создаём другие, с дополнительными «хотелками».
  • Небольшой вес пакета. Для нас это имеет значение, мы не хотим, чтобы продукты из-за наших компонентов прибавляли в весе.
  • Высокая производительность. Под этим мы понимаем гладкость анимации и наименьшее количество перерисовок.
  • Хорошая техническая поддержка. Не всё всегда бывает гладко. У кого-то появились вопросы по работе API, у кого-то выявился баг, а у кого-то расхождение с макетами при использования нашего компонента. На эти случаи мы создали тех. поддержку, где наши разработчики в любую секунду помогут в беде.

Витрина компонентов


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



Здесь мы можем увидеть список всех наших компонентов, информацию по ним, показать все их состояния и возможности.



Тут мы можем увидеть нашу историю изменений. Эта информация берется из файлов CHANGELOG.md, которые генерируются с помощью Rush.



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


Численность и состав


Изначально наша команда состояла из двух frontend (React)-разработчиков, одного дизайнера и одного product owner’а. Сразу хочется пояснить необходимость PO в команде. Человек с этой ролью не только выстраивает процесс и координирует работу команды, но и формирует позиционирование всей дизайн-системы, собирает потребности от других команд для дальнейшего внедрения в UI-KIT и исследует пользовательский опыт с интерфейсами, построенных на наших компонентах, для улучшения UX/UI. С увеличением кодовой базы, численности и масштабности компонентов мы расширились до пяти разработчиков, и не планируем на этом останавливаться.


Заключение


На дизайн системе список активностей команды Web Core не заканчивается. Мы также создаем омниканальные виджеты, такие как навигация по сайту, выбор региона и т.д. Стараемся выработать правила для стандартизации всей кодовой базы в нашей компании. Разрабатываем библиотеки для сбора метрик, авторизации и регистрации. И этот список можно дополнять и дополнять. Я надеюсь, что вы почерпнули что-то новое для себя и своей команды. Очень буду рад обратной связи! Всем спасибо!