Всем привет, меня зовут Ибрагим, я iOS разработчик одной из команд мобильного банкинга и это моя первая статья для Хабра, поэтому прошу строго не судить.

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

Раздробить многолетний монолит? Пфф, делов на 20 минут.
Раздробить многолетний монолит? Пфф, делов на 20 минут.

Как все начиналось

Все началось в одень "прекрасный" день, когда нас снова удалили с AppStore и перед нами стояла цель научиться быстро видоизменять наше приложение, как функционально, так и визуально, чтобы снова опубликоваться в “яблочном” магазине.

Чтобы провернуть такой план, мы решили, раздробить монолит на SPM пакеты. Для себя мы выделили три первых модуля, с которых все началось: 

  • “Ядро”

  • “UI Компоненты”

  • “Компоненты приложения”        

О “Ядре” и “Компонентах приложения” мы поговорим в следующих статьях, если эта статья Вам понравится и будет интересно узнать о нашем опыте. Скажу, что в “Ядро” мы вынесли всю работу сетевого слоя и работу с координаторами (изолировали отдельным таргетом внутри пакета).  В “Компоненты приложения” мы поместили универсальные экраны которые используются по всему приложению, например экран ввода СМС-кода, экран отображения успешной операции и т. п.

Хранение цветов и шрифтов в приложении

Прежде чем приступить к разработке модуля “UI Компонентов”, мы в первую очередь пошли к команде дизайнеров согласовывать нашу будущую дизайн систему, потому что без тесной совместной работы с обеих сторон, создать дизайн систему невозможно. В результате многочасовых споров совещаний, мы выработали ряд правил и договоренностей, следовать которым должна была вся команда, например, одни из которых:

  • все новые экраны в дизайне будут строиться только на компонентах;

  • количество компонентов будет ограничено;

  • новые компоненты будут согласовываться с разработчиками; 

  • не будут создаваться универсальные компонентом для всех нужд;

  • компоненты будут стилизоваться только при помощи стилей, например цвет элемента будет задаваться не напрямую через hex, а через стиль Text.main, который в свою очередь равен определенному цвету, аналогичная история и со шрифтами.   

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

В коде основного таргета приложения, мы в точности повторили две данные структуры UIColors.Branding (отвечает за цветовую палитру) и UIFonts.Brandings (отвечает за шрифты).

Структура UIColors.Branding
Структура UIColors.Branding
Структура UIFonts.Brandings
Структура UIFonts.Brandings

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

Динамические цвета
Динамические цвета

Вы спросите, почему бы не поместить цвета и шрифты внутрь модуля “UI Компонентов”? Иногда на проекте случается редизайн, а когда в проекте не одна сотня экранов (в том числе и легаси), редизайнить все приложение становится очень трудозатратно, поэтому такие процессы происходят постепенно, в несколько релизов. Поэтому для этого создается новая структура для цветов и шрифтов и некоторое количество релизов у вас живет несколько схем. Но Вы скажите, не убедил, все равно можно хранить данные структуры внутри модуля. Рассмотрим другой случай, у нас несколько приложений и все они используют модуль “UI Компонентов”, но каждое приложение имеет свои брендовые цвета и шрифты, в данном случае идеальным вариантом является хранить цвета и шрифты внутри самого приложения.                     

Настройка внешнего вида ui-элементов

Прежде чем идти и верстать наши компоненты нам пришлось научиться применять стили к нашим компонентам. Можно было взять подготовленные структуры цветов и шрифтов и напрямую использовать в компонентах. Данный подход чреват тем, что компоненты не выйдет видоизменять. Также можно было передавать все необходимые цвета, шрифты как параметры в компонент. Но что делать когда нужно ограничить UILabel до трех строк или сделать закругление у UIView, передавать снова параметрами? Эта были бы мега конструкторы, которые не удобно использовать в работе и тем более их поддерживать.

Выпив пару чашек кофе, решили, что необходимо создать публичную структуру Appearance для каждого базового ui-элемента (UILabel, UIButton, UITextField и т.д.) внутри модуля “UI Компонентов”. Данная структура содержит все возможные свойства внешнего вида определенного элемента, которые могут быть изменены разработчиком.  

Appearance для UITextView
Appearance для UITextView

Для удобства использования также была создана публичная функция apply, которая в качестве параметров принимает Appearance и применяет переданные свойства к ui-элементу.       

Применение стилей
Применение стилей

Создание компонентов дизайн системы

После предыдущих подготовок, мы приступили к разработке компонентов дизайн системы. Каждый компонент у нас имеет три составляющих:   

  • Публичную структуру Appearance - содержит все Appearance для используемых ui-элементов

  • Публичную структура Layout - содержит все отступы и размеры необходимые для верстки ui-элементов

  • Публичную структура Content - содержит данные для отображения и также передает callback действий если необходимо.

Структура Layout
Структура Layout
Структура Appearance
Структура Appearance
Структура Content
Структура Content

Для Layout мы подготовили  структуру Spacings, куда вынесли допустимые размеры верстки (кратные двум): XXS - 2pt, XS - 4pt и т. д. Но не согласовали этот момент с командой дизайна и в продакшн это не попало, поэтому это наш небольшой технический долг, который остался после разработки дизайн системы и за который мы скоро возьмемся (наверное, но это не точно).

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

Теперь при разработке нового экрана, в процентах восьмидесяти нам не требуется занимается версткой компонентов, а необходимо лишь выделить компонент Figma, узнать его название,  найти  соответствующий компонент в нашем модуле, вызвать его передав необходимый Appearance и Layout. Готово! Согласитесь, это лучше чем верстать каждый раз, когда нужно создать новый экран. Остальные двадцать процентов - это компоненты, которые относятся к определенному функционалу и не выносятся в общую дизайн систему.            

Хранение стилей в приложении

Для стилей кнопок мы сразу создали два стиля primary и secondary, в каждый из стилей описали состояния внешнего вида: normal, selected, highlighted, disabled, focused.  

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

После чего, решили создать в приложении extension для используемых Appearance компонентов. Теперь нам не нужно писать инициализаторы стилей каждый раз, а необходимо всего лишь вызвать необходимый стиль - UILabel.Appearance.default. После данных манипуляций, на выходе получили папку с расширениями Appearance компонентов, в которой содержатся все стили нашего приложения.      

На этом статья подходит к концу, спасибо, что уделили время, надеюсь, что статья понравилась и наш опыт будет Вам полезен!       

Комментарии (2)


  1. Bardakan
    12.02.2025 08:16

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

    Допустим, вам нужно создать новый экран в красных тонах. У вас в assets уже штук 10 оттенков красного. Вы заставляете дизайнеров использовать строго одни и те же названия цветов? Каждый раз ищете по ассетам, добавлен ли там уже цвет с нужны rgb?

    По этим причинам предпочитаю хранить цвета в коде, но может есть вариант обойти это


    1. ib-khasanov Автор
      12.02.2025 08:16

      Спасибо Вам за вопрос! 

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

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