Нет ничего проще, чем добавить иконку в проект: нужно всего лишь написать дизайнеру, он экспортирует её из Sketch и пришлет вам нужный вариант, а вы используете ее у себя в коде. Если же у вас с десяток проектов, несколько платформ и множество А/Б-тестов на дизайн, то достаточно делать всё то же самое, только в 40 раз чаще и нигде не ошибаться… либо постараться автоматизировать процесс. Под катом — первая часть перевода статьи моего коллеги Cristiano Rastelli про один из примеров такой автоматизации.
Проблема, которую мы решали
Мы в Badoo разрабатываем приложение для знакомств. Вообще-то это несколько приложений, каждое из которых функционирует на нескольких платформах (iOS, Android, Mobile Web, Desktop Web), и работу над ними ведут несколько команд.
При разработке мы используем сотни различных иконок. Некоторые одинаковы в каждом приложении, другие — соответствуют тому или иному бренду. Иногда дизайн меняется, а вместе с ним меняются и иконки: появляются новые, какие-то обновляются, какие-то — удаляются (но часто остаются при этом в кодовой базе).
Созданием и поддержкой иконок занимается наша команда дизайнеров, и когда иконки готовы к работе — дизайнеры обычно отправляли их по email, через чат или облако. Это не только отнимало время, но и зачастую приводило к ошибкам. Если честно, ошибки были каждый раз (все мы люди): иногда иконки обновлялись на одной платформе, но не обновлялись на другой, иногда они пропадали или не соответствовали по формату или размеру. Поэтому дизайнеры и разработчики вынуждены были находиться в постоянном контакте; разработчики экспортировали иконки напрямую из Sketch-файла, и те добавлялись в кодовую базу, но проверки на предмет наличия в базе аналогичных, доступных для повторного использования иконок не проводилось. Уверен, вы хорошо понимаете, о чём я говорю.
У нас в Badoo есть дизайн-система под названием Cosmos, и недавно мы представили мультиплатформенную (Mobile Web, Android и iOS) библиотеку токенов. По сути, теперь изменения в дизайне (например, вид границы кнопки, цвет фона страницы, размер заголовка или продолжительность анимации во всплывающем окне) могут быть описаны с помощью набора параметров, который потом автоматически экспортируется и используется во всех приложениях на всех платформах.
Наше решение, позволяющее за короткое время в несколько кликов трансформировать дизайнерские идеи (например, изменение цвета) в функционирующий код, впечатлило наших продакт-менеджеров и дизайнеров в равной степени. Поэтому следующим их вопросом (а заодно и заданием) было: «А нельзя ли сделать нечто похожее для ресурсов?» Мы ответили: «Да, можно (наверное)».
Должен признать, что сначала мы действовали вслепую. У нас было несколько задумок, но с учётом всех ограничений мы не были уверены в том, что они сработают. Мы решили начать с MVP, но всё прошло так здорово, что проект стал нашим конечным продуктом со всеми необходимыми функциями.
Требования
Требования к MVP-проекту были ясны: инструмент, который на входе получал бы Sketch-файл, а на выходе выдавал все иконки во всех необходимых нам форматах и поддерживал бы вариации иконок для A/B-тестов.
Сложность заключалась в том, что одна и та же иконка имеет разные параметры (цвет, форма) в зависимости от бренда. Ниже представлены несколько иконок для наших приложений. Как видите, какие-то абсолютно идентичны, другие отличаются по ряду параметров, а третьи вообще не имеют ничего общего.
Обратите внимание на то, что используемые в иконках цвета — не просто цвета: они в точности соответствуют указанным в токенах цветам бренда и конкретных фич.
Итак, при разработке инструмента нашей целью было не только автоматизировать создание и доставку иконок для разных платформ и брендов, но и сделать возможной их динамическую колоризацию в соответствии с брендом.
Sketch и SketchTool
Sketch — основной инструмент наших дизайнеров. И, хотя мы рассматривали и другие варианты (например, Figma), мы знали, что в рамках этого проекта будем использовать файлы в формате Sketch (поскольку этим инструментом наши дизайнеры владеют лучше всего и все наши текущие иконки и ресурсы сохранены именно в этом формате).
Фактически в начале проекта мы даже не были уверены, какой формат файлов необходим для платформ. Мы представляли себе процесс примерно так: экспортировать иконки из Sketch-файла в формате SVG, затем «скормить» SVG-файлы версиям для мобильного браузера и Android, а для iOS найти библиотеку, которая конвертирует SVG в PDF. Таким план был изначально, хотя мы и понятия не имели, сработает ли наша задумка и с какими проблемами мы можем столкнуться. В сущности, для этого нам и понадобился MVP — чтобы понять, реализуем ли наш проект, и, если да, насколько он будет трудоёмким.
Не знаю, приходилось ли вам работать с PDF-конвертерами, но мой опыт говорит, что это кошмар. Они всегда почти справляются с задачей, но никогда не делают это на 100%. Поэтому спинным мозгом я ощущал, что мы идём по скользкой дорожке.
Экспорт ресурсов из Sketch проходит идеально — у меня никогда не было проблем с выгрузкой SVG, PDF и любых других форматов. Поэтому я решил выяснить, можно ли взаимодействовать со Sketch по-другому — экспортировать ресурсы напрямую через Sketch, возможно, программным путём (меня также интересовало, можно ли создать кастомный плагин, хотя это и означало бы вагон работы для меня, не имеющего подобного опыта).
Я знал, что внутренняя структура Sketch-файла, по сути, представляет собой архив. Переименовав .sketch в .zip, вы можете открыть файл двойным щелчком; в получившейся папке вы увидите список JSON-файлов и файл для предварительного просмотра в формате PNG.
Итак, я начал изучать JSON-файлы в попытке понять, как они между собой связаны.
Я обнаружил, что, хотя они и имеют большую степень вложенности (и велики по размеру), отношения между различными сущностями внутри объектов не столь запутанны. У вас есть страницы, артборды и слои. Внутри каждого слоя содержатся пути (paths), у которых могут быть общие стили. У каждой из этих сущностей есть уникальный ID, позволяющий сохранить связь между разными файлами; а все страницы сохраняются в JSON-файлах и содержатся в подпапке pages (ID страницы служит именем файла).
В процессе изучения я сделал важное открытие: названия слоёв, страниц и стилей — всего лишь метки, которые можно изменить в любой момент, не нарушая работу внутренней структуры Sketch-файла. Имеет значение лишь привязанный к ним уникальный ID, который не показывается конечному пользователю (хотя его можно читать и ссылаться на него внутри JSON-файлов). Вот образец того, как выглядит уникальный ID стиля:
{
"_class": "sharedStyle",
"do_objectID": "49BA4E98-8D63-435C-81D9-E2F6CDB63136",
"name": "name-of/the-style",
"value": {
"_class": "style",
"endMarkerType": 0,
"fills": [
{
"_class": "fill",
"isEnabled": true,
"color": {
"_class": "color",
"alpha": 1,
"blue": 0.7176470588235294,
"green": 0.4627450980392159,
"red": 0
},
"fillType": 0,
"noiseIndex": 0,
"noiseIntensity": 0,
"patternFillType": 1,
"patternTileScale": 1
}
],
"miterLimit": 10,
"startMarkerType": 0,
"windingRule": 1
}
}
Поэтому я подумал о возможности ввода соглашений о наименовании артбордов и страниц, чтобы сообщать таким образом некую метаинформацию о взаимоотношениях ресурсов и использовать их программным образом во время сборки.
SketchTool
Таким образом, когда первичное исследование было завершено, план «Экспортируем иконки в SVG, а потом конвертируем» превратился в «Сделаем для Sketch плагин, который позволит напрямую экспортировать иконки в конечном формате». Однако и тогда ещё схема работы была довольно размытой (и не факт, что реализуемой).
Изучая исходный код существующих плагинов, я пытался понять, могут ли они взаимодействовать с API экспорта из Sketch, и, если да, то как. И в тот момент я наткнулся на инструмент, о котором прежде не слышал, — SketchTool.
SketchTool — официальный инструмент Sketch (то есть разработанный Bohemian Coding). Согласно документации, он
является утилитой командной строки, идущей в комплекте со Sketch и позволяющей выполнять с документами в формате Sketch определённые действия, например проверять или экспортировать ресурсы. Также она позволяет вам управлять некоторыми функциями Sketch из командной строки — например, запуском плагинов.
Подождите-ка, утилита командной строки, позволяющая выполнять экспорт ресурсов? То что нужно! К тому же, поскольку это официальный инструмент, не должно возникнуть проблем с совместимостью версий, устареванием, поддержкой и т. д.
Я начал изучать утилиту и прочёл всю документацию — единственную страницу на сайте Sketch (в Интернете ей посвящено очень мало материалов, поэтому неудивительно, что я услышал о ней только сейчас).
SketchTool прилагается к Sketch, и её можно найти по адресу:
Sketch.app/Contents/Resources/sketchtool/
Выполнив в терминале команду
$/Applications/Sketch.app/Contents/Resources/sketchtool/bin/sketchtool
, вы получите следующий результат (я немного упростил данные):Usage: sketchtool <command> [<args>]
[--formats=<string>]
[--use-id-for-name{=YES|NO}]
[--export-page-as-fallback{=YES|NO}]
[--serial{=YES|NO}]
[--context=<string>]
[--application=<path>]
[--without-activating{=YES|NO}]
[--item=<string>]
[--items=<string>]
[--safemode{=YES|NO} | --no-safemode | -S {<YES|NO>}]
[--max-size=<float> | -m <float>]
[--background=<string> | -g <string>]
[--compression=<float> | -c <float>]
[--new-instance{=YES|NO}]
[--reveal{=YES|NO}]
[--timeout=<float>]
[--include-symbols{=YES|NO}]
[--bounds=<rectangle>]
[--outputJSON=<path>]
[--filename=<string>]
[--wait-for-exit{=YES|NO}]
[--scales=<path>]
[--overwriting{=YES|NO}]
[--group-contents-only{=YES|NO}]
[--trimmed{=YES|NO}]
[--help]
[--progressive{=YES|NO}]
[--save-for-web{=YES|NO}]
[--output=<path>]
Commands:
dump Dump out the structure of a document as JSON.
export artboards Export one or more artboards
export layers Export one or more layers
export pages Export an area from one or more pages
export preview Export a preview image for a document
export slices Export one or more slices
help Show this help message.
list artboards List information on the document's artboards.
list formats List the supported export formats.
list layers List information on all of the document's layers.
list pages List information on the document's pages.
list slices List information on the document's slices.
metadata List the metadata for a document.
run Run a command from a plugin, inside Sketch.
show Show the location of the various sketch folders.
See ‘sketchtool help <command>’ for more information on a specific command.
Как видите, у инструмента есть четыре основные функции:
read/dump
— прочитать/создать дамп метаданных внутренних JSON-файлов, list
— создать список сущностей файла, export
— экспортировать эти сущности, run
— запустить команду, предоставляемую плагином. В дополнение к этому каждая команда имеет несколько доступных опций. В случае экспорта почти все опции, которые можно найти в соответствующей панели, доступны и в командной строке SketchTool:
Это означает, что SketchTool позволяет использовать для экспорта (например, из SVG в PNG или PDF) непосредственно Sketch, не прибегая к помощи внешних конвертеров. Шикарно!
Быстрый тест с использованием SketchTool и обычного Sketch-файла с несколькими иконками внутри подтвердил наши догадки: благодаря этому простому инструменту мы можем не задействовать для экспорта внешние программы и не писать свои. Sketch может всё!
Файл(ы) Sketch
Когда мы решили, что будем пользоваться Sketch и для хранения, и для экспорта иконок, пришло время собрать используемые в наших приложениях иконки в Sketch-файл.
Изначально мы планировали работать лишь с ограниченным набором иконок, сформированным для MVP-проекта, но быстро поняли, что будет лучше собрать их все, — чтобы сразу устранить дублирование, несогласованность и другие проблемы.
Наши дизайнеры хорошо поработали — и уже через пару дней основная масса ресурсов, используемых ими в Sketch-файлах, была собрана в одном файле. На этом этапе он выглядел так:
У каждой иконки в файле был собственный артборд, названная в соответствии с желаемым названием иконки (впоследствии это же название Sketch даст получившемуся в результате экспорта ресурса файлу). Все пути конвертируются в контуры, а комбинированные пути сводятся в одну фигуру. Благодаря этому сгенерированные ресурсы сохраняют идеальный внешний вид (как в исходном файле) и обладают совместимостью с различными платформами.
Динамическая колоризация иконок с помощью общих стилей (и дизайн токенов)
Следующим шагом после сбора иконок было применение к ним нужных цветов. Мы создали в Sketch набор предопределённых общих стилей (Shared Styles), названия которых соответствовали названиям токенов нашей дизайн-системы, а затем использовали их для раскрашивания иконок.
Вот пример того, как стиль применяется к определённому слою:
А вот как объявляются стили, а затем применяются к элементу:
Ключевую роль играет соглашение о наименовании. Дизайнеры могут управлять стилями в любых подпапках: название стиля задаётся по названию соответствующего токена для этого цвета. Таким образом, впоследствии скрипт сборки может программно оперировать ими.
Названия страниц и артбордов, используемых для A/B-тестирования
Пришло время понять, как дать возможность дизайнерам проводить A/B-тестирование иконок. И вновь мы решили прибегнуть к соглашению о наименовании (я большой поклонник принципа KISS).
В данном случае мы использовали названия страниц для определения тестируемого набора (с помощью префикса XP_), а названия арбордов — для определения, к какому ресурсу относится A/B-тест и к какому именно из его вариантов (указывается в квадратных скобках).
Используемые для теста названия и варианты не придуманы нами — они должны совпадать с уникальными ID, присвоенными тестам и вариантам в нашем собственном инструменте сплит-тестирования. Таким образом, впоследствии ресурсы могут быть корректно сопоставлены с конкретной пользовательской группой.
Несколько файлов для нескольких брендов
Последнее что нас интересовало, — как поддерживать разные формы одной и той же иконки для разных брендов?
Нашим продакт-менеджерам соблюдение этого требования было очень важно, и у нас было несколько вариантов. Сначала мы хотели использовать разные страницы одного Sketch-файла, которые были бы названы в соответствии с брендом. Но вскоре поняли, что это усложнит жизнь дизайнерам: им будет нелегко постоянно синхронизировать иконки разных брендов. Так что мы решили использовать несколько файлов: общий файл, где будут храниться все иконки, не меняющиеся в зависимости от бренда, и файлы для каждого бренда, заменявшие бы «базовые» иконки из общего файла.
Наши Sketch-файлы готовы! Пришёл черед написания кода.
Читать продолжение