- PVSM.RU - https://www.pvsm.ru -
Дизайн — это фашизм. Фашизму нужна питательная среда. Он начинает раскрываться в полной мере только на крупных масштабах. Идеальная среда для фашизма — это большая компания с огромным количеством продуктов. Например, Google или… Альфа-Банк. Фашизм априори не гибок…
Все кнопочки на всех продуктах компании должны носить одинаковые рубашки, только одного номенклатурного цвета #F02823. Любая ссылка также имеет свою униформу: цвет #0A1E32, нижнее подчеркивание на расстояние 2px. Если мы нажмем на ссылку, она должна незамедлительно выполнить команду — перенести нас на другой раздел приложения. За неподчинение — изгнание из дизайна системы Альфа-Банка в Зеленый Банк или расстрел. И неизвестно, что бы в этом случае выбрала ссылка.
Но это фашизм во имя Любви. Мы любим своего пользователя: мы хотим, чтобы на каждом нашем продукте пользователь получал одинаковый опыт. Чтобы ему было легко и просто. Чтобы Банк быстро и эффективно решал его задачи.
Дизайн — это фашизм во имя Любви.
Это фашизм ради драйва и скорости. Мы хотим разрабатывать наши приложения быстро, чтобы разработчики не изобретали каждый раз велосипед для новых приложений и могли шарить лучшие UI/UX-практики между командами.
Любой фашизм предполагает идеологию. Любой фашизм предполагает централизованное принятие решений. Для любого фашизма компании необходимо завести Самый Главный Комитет по Цензуре и Унификации или СГКпЦиУ.
Но, подождите, теперь Альфа-Банк — это бирюзовая компания, в движок которой зашит манифест Agile и Scrum. Это означает, что мы осознанно приняли стратегию, что все решения «зашиты» в команды, а не в комитеты по типу СГКпЦиУ…
Наша библиотека компонентов ARUI Feather [1] базируется на двух хорошо знакомых решениях из мира фронтенда: БЭМ [2] методологии и React [3].
Здесь не будет рассказа про выбор инструментов: мне больше хочется рассказать про принципы и практики масштабирования дизайн-систем, которые мы выработали в процессе создания ARUI Feather [1].
Подробнее о том, почему у нас именно БЭМ методология [2] + React [3], можно узнать из этого видео с Яндекс.Деньги FrontendMix 2017 [4].
В основе инженерных решений ARUI Feather [1] лежит философия
KISS [5] / YAGNI [6] / DRY [7].
KISS [5] означает, что мы изначально для себя решили избегать сложных решений. Перед нами стояла задача сделать код дизайн-системы, в котором сможет разобраться самостоятельно любая команда. ARUI Feather [1] — это АК-47 мира дизайн-систем. Даже лежа по уши в песке в окопах под Багдадом, вы можете самостоятельно разобрать и собрать ее, не обращаясь в сервис-центр ВМС США.
Также, следуя YAGNI [6], мы делаем только необходимое, и последний тренд — мы чаще удаляем компоненты, чем создаем новые, потому что на самом деле многие вещи лежат за зоной ответственности дизайн-системы.
ARUI Feather [1] — это АК-47 мира дизайн-систем. Даже лежа по уши в песке в окопах под Багдадом, вы можете самостоятельно разобрать и собрать ее, не обращаясь в сервис центр ВМС США.
По этой причине мы используем БЭМ-методологию [2] не в полной реализации, исключая из нее миксы [8] и уровни переопределения [9]. Оба эти подхода про “смешивание”, что при масштабировании включает на проектах “безумный миксер”, делая код тяжелым для отладки.
Технически мы поддерживаем дизайн-систему через наше собственное Open Source решение — cn-decorator [10], которое позволяет использовать БЭМ методологии [2] и React [3] вместе.
Мы используем БЭМ методологию [2] не в полной реализации,
исключая из нее миксы [8] и уровни переопределения [9].
В Альфа-Банке уже более 30 команд, которые разрабатывают своей фронтенд независимо, используя ARUI Feather [1] и cn-decorator [10].
У нас нет отдельной выделенной команды, которая сконцентрирована на разработке UI/UX библиотеки. Разработка ведется по принципам сложившимся в Open Source: есть мейнтейнеры библиотеки компонентов, есть контрибьюторы и есть, конечно, пользователи. И все эти люди так или иначе участники разных команд. Мы осознанно пошли на этот шаг, чтобы избежать появления в компании узкого звена в виде команды разработки библиотеки, которой другие команды делают заказ и ожидают, когда им помогут.
Также это помогает решать задачи, которые действительно важны для создания продукта, а не задачи из вакуума, которые часто любят себе выдумывать сервисные команды.
Далее я расскажу про топ вопросов от команд, которые поступают мейнтейнерам, и как мы их решаем…
Так выглядит самый простой компонент, написанный с использованием cn-decorator [10].
import cn from 'cn-decorator';
@cn('button')
class Button extends React.Component {
render(cn) {
return <button className={ cn() } />;
}
}
Достаточно просто использовать декоратор @cn и передать название блока, в данном примере ‘button’. Теперь метод render получит свой экземпляр cn, который может быть использован для генерации имен классов. И наш финальный БЭМ блок в HTML будет выглядеть приблизительно так:
<button class="button"></button>
Но ведь в БЭМ-методологии [2] есть еще элементы, модификаторы, миксы и уровни переопределения… Пример чуть сложнее:
import cn from 'cn-decorator';
@cn('button')
class Button extends React.Component {
render(cn) {
return (
<button className={ cn({ disabled: true }) }>
<span className={ cn('text') }>Text</span>
</button>
);
}
}
В результате у нас получается следующая верстка:
<button class="button button_disabled">
<span class="button__text">Text</span>
</button>
На примере наглядно показано, как cn-decorator [10] умеет обращаться с модификаторами и элементами. Остается добавить немного CSS, и компонент готов!
Альфа-Банк — это на 100% продуктовая компания. Наши команды на регулярной основе проводят десятки экспериментов. Иногда даже небольшое изменение цвета рамочки может привести к изменению конверсии.
Если бы у нас был комитет СГКпЦиУ, то нам бы пришлось вынести решение об таком незначительном эксперименте на его ближайшее собрание, дождаться вердикта и, спустя долгие полгода, все-таки повысить конверсию. Технически мы бы использовали WebComponents и запретили бы любое вмешательство в верстку и API компонента.
Но жизнь богаче, и каждая из команд имеет полное право на проведение экспериментов с дизайном. Для этого в cn-decorator [10] встроен механизм className proxy…
import Button from 'arui-feather/button';
class App extends React.Component {
render() {
return <Button className="my-class" />;
}
}
В результате мы получаем следующую верстку:
<button class="button my-class"></button>
Теперь мы можем просто на проекте в селекторе .my-class перекрыть пару свойств нашей кнопки…
И такое случается. Согласитесь, обидно писать компонент, логика работы которого тебя полностью устраивает, но выглядит он совершенно по-другому. Чуть выше я говорил о том, что мы не любим все паттерны смешивания, а предпочитаем паттерны на основе композиции. Поэтому у нас есть механизм перегрузки имени блока, который позволяет разобрать компонент на составные части: стили и логику.
На этой картинке две кнопки. Они выглядят совершенно по-разному, тем не менее шарят между собой все поведение. Мы добиваемся этого тем, что умеем перегружать базовое имя блока.
Достаточно просто передекорировать компонент и написать для него новые стили:
import cn from 'arui-feather/cn';
import Button from 'arui-feather/button';
import './tag-button.css';
@cn('tag-button')
class TagButton extends Button {};
Результирующая верстка TagButton:
<button class="tag-button tag-button_disabled">
<span class="tag-button__text">Text</span>
</button>
Такой несложный паттерн позволяет нам шарить логику компонента между разными представлениями.
Это были простые примеры, но часто наши компоненты составные (помните, мы любим композицию). Например, таким составным компонентов является Select: он состоит из двух компонентов Button и Popup.
Приблизительно так выглядит код Select:
import cn from 'arui-feather/cn';
import Button from 'arui-feather/button';
import Popup from 'arui-feather/popup';
@cn('select')
class Select extends React.Component {
render(cn) {
return (
<div className={ cn() }>
<Button />
<Popup />
</div>
);
}
}
Но иногда командам нужно поменять составной компонент. Например, команде нужно, чтобы Popup выпадал из ссылки, а не из кнопки. Приблизительно так:
Но у нас модульная система на ES6 modules. Единственная возможность заменить составной компонент — это сделать патч на уровне сборки. Здесь на помощь снова приходит cn-decorator [10] и его фича Dependency Injection Components. Давайте передадим наши составные компоненты через cn:
import cn from 'arui-feather/cn';
import Button from 'arui-feather/button';
import Popup from 'arui-feather/popup';
@cn('select', Button, Popup)
class Select extends React.Component {
render(cn, Button, Popup) {
return (
<div className={ cn() }>
<Button />
<Popup />
</div>
);
}
}
Теперь мы можем сделать собственный Select, заменив в нем Button на наш собственный.
import cn from 'arui-feather/cn';
import Select from 'arui-feather/select';
import Popup from 'arui-feather/popup';
import MyLinkButton from './my-link-button';
@cn('my-link-select', MyLinkButton, Popup)
class MyLinkSelect extends Select {};
Ура! Теперь мы можем менять любой составной компонент композиции!
Дизайн-система в большой компании — это не про технологии: это не про холивар Angular vs БЭМ vs React. Дизайн система — это поиск компромиссов между консистентностью и возможностью проводить быстрые эксперименты. Дизайн система — это работа с комьюнити и работа с бизнес-требованиями одновременно. Это b2b- и b2c-решение: на одной чаше весов бизнес, который хочет быстро, дешево и качественно, и с другой стороны разработчики, которые хотят гибко, расширяемо, но предсказуемо и надежно.
Хочется завершить эту статью одним очень точным законом, который лучше всего объясняет архитектуру дизайн-систем (да и в принципе любую архитектуру):
«Организации, проектирующие системы (здесь имеется в виду более широкое толкование, включающее не только информационные системы), неизбежно производят конструкцию, чья структура является копией структуры взаимодействия внутри самой организации»
—Закон Конвея
Наши Open Source-решения:
Автор: GREENpoint
Источник [11]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/javascript/266398
Ссылки в тексте:
[1] ARUI Feather: https://github.com/alfa-laboratory/arui-feather
[2] БЭМ: https://ru.bem.info/
[3] React: https://reactjs.org/
[4] этого видео с Яндекс.Деньги FrontendMix 2017: https://www.youtube.com/watch?v=yfIsPH1jXJc
[5] KISS: https://ru.wikipedia.org/wiki/KISS_%28%D0%BF%D1%80%D0%B8%D0%BD%D1%86%D0%B8%D0%BF%29
[6] YAGNI: https://ru.wikipedia.org/wiki/YAGNI
[7] DRY: https://ru.wikipedia.org/wiki/Don%E2%80%99t_repeat_yourself
[8] миксы: https://ru.bem.info/methodology/key-concepts/#%D0%9C%D0%B8%D0%BA%D1%81
[9] уровни переопределения: https://ru.bem.info/methodology/redefinition-levels/
[10] cn-decorator: https://github.com/alfa-laboratory/cn-decorator
[11] Источник: https://habrahabr.ru/post/340522/
Нажмите здесь для печати.