Привет, Хабр. Меня зовут Роман, я работаю в группе проектирования пользовательских интерфейсов для B2B-решений «Лаборатории Касперского». В какой-то момент мы столкнулись с определенным хаосом в хранении и доступности материалов. Дизайнер всегда помнит, где лежат его макеты. Аналитику, разработчику и тестировщику приходится искать их в комментариях к задачам, в чатах и в тяжелых релизных файлах, где нужной страницы может просто не оказаться.

Чтобы решить эту проблему, мы перестроили дизайн-документацию продукта в Pixso: мастер-макет повторяет мейн, у каждой задачи свой файл, а на релизе все раскладывается по местам одним действием. Я хочу поделиться нашим опытом и рассказать, как это устроено, где схема пока проседает, а также поделиться чек-листом для тех, кто захочет повторить наш вариант у себя.
Проблема начинается за пределами дизайна
У нас в трекере есть BRQ — большое требование на фичу. Оно служит родителем для всех задач помельче: архитектуры, бэкенда, фронта, тестирования и дизайна. Аналитик открывает BRQ, идет в дизайн-задачу, и дальше все зависит от везения… Ссылка на макет может найтись в мартовском комментарии, в рабочем чате, в личной переписке или в письме. А может не найтись вообще, и тогда человек идет писать дизайнеру в личку.
Чтобы решить эту проблему, первым делом я сделал шаблон дизайн-задачи, в котором самое первое поле всегда называется ДИЗАЙН-МАКЕТ. Это одно фиксированное поле в одном и том же месте, без вариаций вроде «Ссылки» или «Материалы». Архитекторы, аналитики и разработчики знают, что макет всегда лежит именно там.
Но так лечится только симптом. Ссылка ведет в Pixso, а внутри Pixso хватало своих проблем.
Как было: один файл на релиз
Раньше на каждый релиз заводился один большой файл РЕЛИЗ X, а внутри него лежали страницы с названиями доработок: «Запись и скачивание трафика», «Добавление фильтра на страницу Событий» и так далее. Единого стандарта названий не было, поэтому по имени страницы не всегда удавалось понять, какие экраны продукта затрагивает задача.
У такого подхода один плюс: виден скоуп версии. Открываешь файл и сразу видишь все, что делалось в релизе. Минусов четыре, и по природе они очень разные.
Файл тяжелый. Он долго открывается и тормозит.
Нет состояния «как сейчас». Допустим, нужно посмотреть, как выглядит страница отчетов. Если в этом релизе ее не трогали, в файле ее просто нет. Идешь в предыдущий релиз, потом в тот, что был до него.
Нет карты продукта. Непонятно, какие продуктовые страницы вообще есть в актуальных макетах, а какие никогда не рисовались. Экраны спрятаны внутри задач, задачи названы по фичам, и найти конкретный экран по названию невозможно.
Нет поиска по задаче. Просят показать макет по задаче 10000, и сначала приходится вспоминать, в каком релизе она была.
Переименованием папок эти боли не вылечить. Первая проблема связана с производительностью. Вторая и третья появляются потому, что у документации нет среза «как есть». Четвертая упирается в отсутствие индекса.
Два принципа
Все, что я сделал дальше, вытекает из двух правил.
Состояние и изменения хранятся отдельно
Релизный файл пытался быть одновременно снимком продукта и журналом изменений, но ведь требования у этих ролей противоположные. Снимку нужны полнота и стабильность, журналу — привязка к задачам и хронология, поэтому файл не справлялся ни с одной из них.
Имя и расположение файла работают как индекс
Имя файла рассказывает, что внутри, но его главная задача шире: оно отвечает на вопрос «как меня найти». Расположение отвечает на вопрос «на какой я фазе релизного цикла».
Отсюда следуют все остальные правила: ID задачи стоит первым токеном, версия при необходимости добавляется префиксом, папку определяет фаза цикла.
Как устроено сейчас
Мастер-макет
Мастер-макет повторяет структуру продукта: его страницы совпадают со страницами продукта. В нем лежит только то, что уже попало в мейн, то есть принято, смерджено и уйдет пользователям с ближайшим релизом. Запланированное и даже согласованное, но еще не смердженное, в мастер не попадает. Лежит он в папке «РЕЛИЗЫ / ПРОДУКТ v.2».
Правило «только из мейна» работает как страховка. Пока задача не смерджена, в мастере ее нет, поэтому если она выпадет из релиза, ничего не сломается и выковыривать из макета ничего не придется.
Это же правило закрывает еще одну старую проблему. Бывало, что часть фичи согласовали, в нескольких задачах нарисовали поверх нее доработки, а потом согласованную часть вырезали из скоупа. До продукта она так и не дошла, но в макетах осталась мертвым грузом. Когда следующие задачи добирались до разработки, у команды возникали вопросы: поверх чего нарисован макет и где состояние as is?
Состояние «что на проде у клиентов» тоже никуда не девается. Это предыдущий релизный мастер, «ПРОДУКТ v.1». Получаются два состояния в двух файлах, которые и так существуют.
Файлы задач
На каждую дизайн-задачу заводится отдельный файл с именем по шаблону <ID задачи> <название задачи>, например «10000 Название задачи». Внутри всегда две страницы: drafts и handover. На handover лежит финальный согласованный вариант всего, что делалось по задаче: все экраны, состояния и комментарии. Ссылка из трекера ведет именно на handover конкретного файла.
Файлы задач лежат в рабочей директории ПРОДУКТ, на одном уровне с папками РЕЛИЗЫ, АРХИВ и папкой с библиотекой компонентов. Это задачи текущей версии, то есть все, что делается поверх релизной версии.
Архив
Когда задача уезжает в релиз, ее файл получает префикс версии и переезжает в АРХИВ: «10000 Задача» превращается в «v1 10000 Задача». Это минимальный вариант: один мастер-файл на версию и общий архив, где версии различаются по префиксу.

Когда страниц и состояний становится много, мастер режется по разделам продукта, а архив — по версиям:

Жизненный цикл
Мастер-макет живет непрерывно, как ветка, которая всегда совпадает с мейном. Задачи вливаются в него по ходу цикла, как только уезжают в мейн.
Заново собирать мастер к релизу не нужно. Релиз делает три вещи:
копирует мастер в РЕЛИЗЫ как срез того, что ушло клиентам;
проставляет файлам задач префикс версии и переносит их в АРХИВ;
очищает рабочую директорию.
Сам мастер при этом продолжает жить, уже для следующей версии.

Что это дает на практике. Референс «как сейчас» существует всегда и не зависит от истории задач. Задачу находят по номеру в имени файла: текущие лежат в корне, прошлые в архиве. Файлы остаются легкими.
Старт задачи превращается в ритуал, где ничего не нужно изобретать. Дублируешь шаблон с готовой внутренней структурой, забираешь из мастера референсные страницы и работаешь поверх них.
Самое ценное в схеме то, что всю реорганизацию запускает одно событие, релиз. Никому не приходится каждый день решать, куда положить файл. Состояние директории определяется фазой цикла и не зависит от дисциплины отдельного человека.
Как часто вливать задачи в мастер
Сливать рабочие макеты с мастером один раз за релиз не обязательно. Частота слияния работает как регулятор, и настраивать его стоит под поток задач.
Поток задач |
Когда вливать в мастер |
Почему |
Несколько задач за цикл, релизы частые |
На релизе, одним заходом |
Пул не успевает разрастись, отдельный ритм не нужен |
Задачи идут постоянно, релиз раз в полгода-год |
Регулярно — раз в спринт или по накоплению N файлов |
Иначе к релизу накапливается слияние, которое руками уже не сделать |
Ориентир простой: количество невлитых файлов в корне рабочей директории. Если их стало больше, чем можно спокойно окинуть взглядом, пора вливать, не дожидаясь релиза.
При годовом цикле это критично. Мастер, который обновляется раз в год, к середине цикла отстает от продукта на полгода, а слияние в конце превращается в неделю ручной работы. Если размазать слияние по циклу, суммарно оно обойдется так же, но платить придется порциями минут по двадцать, и пика в самый загруженный момент не будет.
Дробить, когда заболит
Частый вопрос: мастер должен быть одним файлом или набором файлов по разделам? И архив лучше держать общей папкой или сразу разбить на подпапки по версиям?
Ответ для обоих случаев одинаковый: как понадобится. Если все страницы помещаются в один мастер и он не грузит процессор, хватит одного файла, как на первой схеме. Если страниц и состояний очень много, «ПРОДУКТ v.2» становится папкой с файлами по разделам. С архивом так же: десяток файлов спокойно живет в общей папке с префиксами, сотню уже стоит разбить по версиям.
Это осознанный отказ от преждевременной декомпозиции. Структура, нарезанная на вырост, каждый день требует денег и усилий, а окупается неизвестно когда. Правило именования при этом остается прежним, меняется только глубина вложенности.
Три неочевидных решения
Две задачи правят одну страницу. Звучит как страшный сценарий, но в моей практике он встречается редко. К тому же у него есть арбитр. Дизайн вливается в мастер только после того, как ветки слились с мейном, поэтому разработка столкнется с тем же конфликтом раньше дизайнера. В спорных местах достаточно посмотреть, как сделано в мейне. Что делать с такими пересечениями в команде из нескольких дизайнеров, расскажу ниже.
Библиотека компонентов живет вне цикла версий, она всегда актуальна. Старые задачи в архиве и старые мастер-макеты просто не обновляют версии компонентов. Благодаря этому в библиотеке не нужно следить за обратной совместимостью: архив замораживается сам собой.
Мастер v.0 собирается постепенно. Это самый дорогой вход в схему, и проходить его за один присест необязательно. На релизе v.0 мастер собирается из тех задач, что есть под рукой, а дальше обрастает страницами по ходу работы над следующими версиями.
Когда дизайнеров несколько
На одном дизайнере схема работает сама собой. В команде появляются наложения: две задачи независимо друг от друга трогают одну и ту же страницу. Прежде чем городить процесс, стоит различить три случая, потому что лечатся они по-разному.
Тип наложения |
Пример |
Чем лечится |
Компонент |
Обе задачи трогают таблицу или модалку |
Не конфликт задач. Правка уезжает в библиотеку, обе задачи подтягивают обновленный компонент |
Соседство на странице |
Одна правит шапку, другая — таблицу той же страницы |
Механический конфликт, разрешается при слиянии за минуту |
Одна зона |
Обе переделывают одну и ту же таблицу |
Настоящий конфликт: нужно продуктовое решение, а не процедура |
Первый тип встречается чаще всего и устраняется дешевле всего. Если наложения регулярно приходятся на компоненты, структура файлов ни при чем. Значит, компоненты живут в макетах задач и не доходят до библиотеки.
Заводить отдельный реестр занятых страниц не стоит. Это еще один процесс, о котором надо помнить, и его забудут первым. Нужные списки уже существуют.
Список «в разработке» состоит из файлов в корне рабочей директории, они и так перед глазами. Список «в мейне» можно получить из трекера: какие дизайн-задачи уже заехали в мейн. В каком виде получать такую выборку регулярно, фильтром или выгрузкой, стоит договориться с командой разработки. Пока этого нет, статус приходится выяснять вручную, и для команды это самое слабое место схемы.
Правило приоритета такое: побеждает тот, кто раньше уехал в мейн. Второй дизайнер ничего не переделывает, он просто берет референс из handover первой задачи вместо мастера. Так N параллельных правок одной страницы выстраиваются в цепочку, и сливать в мастер нужно только последнее звено.
Оговорка: правило работает, только если дизайнеры синхронизируются между собой и второй узнает, что первый уже сдал работу. В маленькой команде хватает разговора, в большой нужен механизм. Какой именно, пока открытый вопрос.
Что пока не решено
Без честного списка слабых мест статья выглядела бы как реклама, поэтому вот они.
Слияние делается вручную. Это главный минус схемы. Нет diff, нет проверки, нет CI. Если при вливании потерялась страница, узнаешь об этом не сразу. Регулярный ритм делает каждую порцию слияния маленькой, но сам риск остается.
Мастер может разойтись с реализацией. Разработка сделала иначе, дизайнер об этом не узнал, и мастер начинает врать. А доверие к мастеру и есть весь смысл схемы. Частично это ловит дизайн-ревью перед релизом, когда дизайнер проходит по реализованным экранам и сверяет их с макетом. Но ревью налажено не во всех процессах, и там, где его нет, расхождения всплывают случайно.
Файлы-исключения. Рано или поздно в корне появляется файл без ID: наброски, исследование, черновик для обсуждения. Со временем таких файлов становится больше, и они ломают правило «все, что лежит в корне, относится к задачам текущей версии». Решение простое: завести папку-«песочницу» для драфтов и держать ее рядом с РЕЛИЗАМИ и АРХИВОМ. Тогда правило корня остается нерушимым, а у всего внесистемного появляется законное место.
Чек-лист для тех, кто хочет повторить
Добавьте в шаблон дизайн-задачи фиксированное поле для макета и поставьте его первым.
Давайте ссылку прямо на страницу handover внутри файла.
Начинайте имя файла задачи с числового ID, название пишите после него.
Называйте служебные папки на одном языке и в одном регистре.
Заведите файл-заготовку со страницами drafts и handover и создавайте новые файлы только из нее.
Заведите папку-«песочницу» для драфтов и всего внесистемного.
Кладите в мастер только то, что уже в мейне. Состояние на проде у клиентов хранит предыдущий релизный мастер.
Вливайте задачи в мастер по размеру пула невлитых файлов, без привязки к календарю.
Собирайте мастер v.0 постепенно.
Дробите мастер и архив, когда заболит, и не раньше.
Если вы решали ту же задачу по-другому, особенно синхронизацию нескольких дизайнеров, расскажите в комментариях. Для нас это пока самый открытый вопрос.