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

Как оно обычно бывает — продукт состоит из модулей, модули состоят из экранов (экраны состоят из блоков, а блоки из компонентов). Все это обвязывается флоу, в которых дизайнер показывает переходы между экранами в рамках конкретных сценариев. И, вроде бы, все счастливы.

Нужно представить, что тут не варфреймы, а вот прям настоящие макеты экранов. На остальных картинках тоже.
Нужно представить, что тут не варфреймы, а вот прям настоящие макеты экранов. На остальных картинках тоже.

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

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

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

Изолируем макеты

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

  • Аккаунт;

  • Платежи и переводы;

  • Аналитика (как без нее то);

  • Настройки.

Вот эти разделы и станут основными модулями. Условимся, что модуль — это набор связанного по смыслу функционала.

Вводим следующее правило — за каждым экраном закрепляется модуль. Актуальный дизайн экрана может находиться только в фигма-файле модуля и больше нигде. Такое вот крепостное право.

Примерчик

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

Возьмем простенький сценарий:
— Пользователь, листая список операций в аналитике, открывает информацию о транзакции и решает повторить платеж. Он тыкает кнопку на экране транзакции и попадает в раздел "Платежи и переводы" с предзаполненными параметрами платежа, подтверждает транзакцию ОТП-кодом и видит саксесс-скрин у нас все платежи проходят.

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

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

В кнопку вшита ссылка, тыкнул на нее и улетел к нужному флоу
В кнопку вшита ссылка, тыкнул на нее и улетел к нужному флоу

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

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

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

Декомпозируем модуль

Чтобы макеты в рамках модуля было проще описывать, передавать в разработку и, даже, версионировать, стоит разделить модуль на подмодули. Сразу должно стать совсем хорошо.

Обычно у модуля есть несколько пользовательских задач, которые он обслуживает. Например, модуль "Платежи и переводы" в нашем банковском приложении должен позволять пользователю вводить реквизиты платежа, подтверждать действие OTP-кодом и уметь сообщать о результате операции. Ну, еще должен быть какой-то экран, с которого пользователь сможет запустить нужный ему сценарий — экран со списком всех доступных платежей и переводов (где у нас будет только "Оплатить воду").

Получается, нам нужны следующие штуки:

  • Какая то штука, где можно посмотреть список доступных операций;

  • Какая то штука для ввода реквизитов;

  • Какая то штука для вывода статуса операции.

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

Примечательно, что этим штукам вообще не обязательно знать о существовании друг друга. Такая изолированность делается вот для чего.

— Раз, и мы стали подтверждать платеж, рисуя пальцем сердечко на экране. Имеет ли это хоть какое-то отношение к штукам для ввода реквизитов или вывода статуса — не думаю.

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

Суть микромодуля

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

Штука для "подтверждения действия" должна уметь встраиваться в любой флоу где требуется подтверждение действия. Потому что она умеет подтверждать действие, а больше ничего не умеет — только предоставлять инпут для ввода пароля и говорить ок/не ок. Ну, может еще инициировать отправку кода еще разок, если хорошенечко его попросить :) В нужном куске сценария микросервис микромодуль примет управление этим сценарием, обработает действия пользователя и, при необходимости, передаст управление следующему элементу цепочки.

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

Такой подход кажется очевидным для штук вроде СМС-валидации, но есть мнение, что он применим ко всем задачам, решаемых приложением. Некоторые микромодули переиспользуются часто, некоторые почти никогда, и это ок.

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

Важно! Логика работы и обрабатываемые кейсы микромодуля описываются в рамках его документации. Стейты входящих экранов описываются через описания блоков и стейтов этих блоков. Никаких 100500 макетов главного экрана, чтобы показать состояния ховера для всех кнопок поисковой строки или разные состояния виджета. В документации необходимо описать достаточно контекста, чтобы четко понимать что микромодуль умеет и где уместно его использовать. Тогда все будет хорошо.

Версионность

Деление на модули позволяет получить некое подобие фигма-версионности.

Немного поясняющего нытья

Без такого деления вообще непонятно что, где и каким образом версионировать — экран, компонент, флоу или все сразу. Речь, конечно, про хранение этих артефактов в фигме. У дизайнеров нет контроля версий, мы не можем откатиться на предыдущую версию чего-угодно, взять ее и работать в новой ветке. Веток у нас тоже нет. Выгрузка в зеплин и использование версионности в нем еще больше раздувает объем дизайн артефактов. Сторибук и другие достижения высших цивилизаций — это по большей части решение проблемы для стороны разработки. Ответ на вопрос как дизайнеру поддерживать актуальные макеты в фигме, смотреть на шаг вперед и шаг назад, они, похоже, не дают. Ну или я пока не разобрался как :(

У каждого модуля есть три версии — три пейджа в файле:

  • PR (Prod) — что уже есть на проде

  • СR (Сhange request) — что в ближайшем будущем будет на проде

  • TС (Target condition) — мысли о том, что уедет в следующие CR и к чему мы вообще идем.

Каждая версия состоит из нужных версий соответствующих микромодулей. Например, всего в модуле 10 микромодулей, в ближайшем CR изменения затрагивают только три из них, значит на странице CR будет только 3 этих микромодуля.

Как только CR релизится, модули в PR меняются на актуальные, а в CR насыпаются изменения для следующей фичи.

Что в итоге

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