Использовал ли инструменты кодогенерации, такие как Sourcery?

Ответ

Да, активно использовал Sourcery — инструмент для метапрограммирования в Swift, который генерирует код на основе аннотаций в исходниках и шаблонов (Stencil).

Типичные сценарии применения:

  • Автоматизация boilerplate-кода: Генерация реализаций протоколов Equatable, Hashable, Codable для моделей.
  • Моки для тестирования: Автоматическое создание мок-объектов, которые реализуют протоколы зависимостей, что упрощает unit-тестирование.
  • Линтинг и проверки: Генерация кода для проверки, что все случаи в enum обработаны в switch.
  • Динамические шаблоны UI: Генерация кода для таблиц или коллекций на основе моделей данных.

Пример шаблона Sourcery (.stencil) для автоматической генерации Equatable:

// AutoEquatable.stencil
{% for type in types.structs|enum where type.implements.Equatable %}
// MARK: - AutoEquatable for {{ type.name }}
extension {{ type.name }}: Equatable {
    static func ==(lhs: {{ type.name }}, rhs: {{ type.name }}) -> Bool {
        {% for variable in type.storedVariables %}
        guard lhs.{{ variable.name }} == rhs.{{ variable.name }} else { return false }
        {% endfor %}
        return true
    }
}
{% endfor %}

Аннотация в исходном коде Swift, которая активирует шаблон:

// sourcery: AutoEquatable
struct User {
    let id: Int
    let name: String
    var email: String?
}

Преимущества:

  • Снижение рутинной работы и ошибок при написании повторяющегося кода.
  • Единообразие сгенерированного кода по всему проекту.
  • Упрощение рефакторинга — при изменении модели достаточно перегенерировать код.

Недостатки / сложности:

  • Настройка в CI/CD: Генерацию нужно интегрировать в процесс сборки (например, как Run Script Phase в Xcode).
  • Отладка: Сложнее отследить источник ошибки, если она в сгенерированном коде. Необходимо проверять шаблоны и входные аннотации.
  • Зависимость от инструмента: Добавляет ещё одну зависимость в проект.

Ответ 18+ 🔞

Слушай, а вот этот ваш Sourcery — это ж просто песня, а не инструмент! Ну, в смысле, метапрограммирование в Swift, когда код сам себе код пишет. Представляешь? Сидит такой код, пьёт кофе, и параллельно штампует себе подобных. Красота!

Где эту штуку впихивали, чтобы жизнь мёдом не казалась:

  • Автоматизация скукотищи: Вместо того чтобы вручную, как обезьяна, писать Equatable, Hashable, Codable для каждой своей структурки — он это делает за тебя. Ты просто аннотацию накатал, а он уже тебе готовый extension подсовывает. Волшебство, ёпта!
  • Моки для тестов: О, это вообще отдельная история. Надоело для каждого протокола-зависимости городить свой мок-объект с кучей заглушек? Sourcery берёт протокол и генерирует тебе готового солдатика-заглушку. Unit-тесты пишутся почти сами, блядь.
  • Линтинг на стероидах: Можешь заставить его генерировать код, который проверит, не забыл ли ты в каком-нибудь switch обработать все кейсы enum. Типа превентивный удар по будущим багам.
  • UI из коробки: Если у тебя таблицы или коллекции строятся по однотипным моделям, можно шаблон накатать, и он тебе ячейки, datasource и прочую муть сгенерирует. В общем, лень — двигатель прогресса, а Sourcery — её верный слуга.

Вот, смотри, как это выглядит изнутри. Шаблон (.stencil) для автоматического Equatable:

// AutoEquatable.stencil
{% for type in types.structs|enum where type.implements.Equatable %}
// MARK: - AutoEquatable for {{ type.name }}
extension {{ type.name }}: Equatable {
    static func ==(lhs: {{ type.name }}, rhs: {{ type.name }}) -> Bool {
        {% for variable in type.storedVariables %}
        guard lhs.{{ variable.name }} == rhs.{{ variable.name }} else { return false }
        {% endfor %}
        return true
    }
}
{% endfor %}

А в твоём коде ты просто вешаешь волшебную бирочку:

// sourcery: AutoEquatable
struct User {
    let id: Int
    let name: String
    var email: String?
}

И всё! Sourcery это видит, шаблон применяет, и бац — у User появляется реализация ==. Чистая магия, только без факира.

Что хорошего, спросишь?

  • Рутины и ошибок — ноль ебать. Перестаёшь тупо копипастить одно и то же. Мозг освобождается для действительно важных вещей. Например, чтобы подумать, почему этот блядский API опять отдаёт 500-ю ошибку.
  • Всё единообразно. Сгенерированный код по всему проекту выглядит одинаково, не как у страшного Змея Горыныча — три головы, три разных почерка.
  • Рефакторить не страшно. Добавил поле в модель? Не надо бегать по всему проекту и править ==, hash, encode. Просто перегенерировал код — и порядок. Удивление пиздец, как жили без этого раньше.

Но и подводных ебуч, конечно, хватает:

  • Настройка в CI/CD. Это тебе не вручную кнопочку ткнуть. Надо интегрировать генерацию в процесс сборки, обычно как Run Script Phase в Xcode. Если накосячишь — проект не соберётся, и вся команда будет тебя ненавидеть. Ответственность, блядь!
  • Отладка — тот ещё квест. Если ошибка в сгенерированном коде, искать её источник — это как искать иголку в стоге сена, который сам себя сгенерировал. Придётся лезть в шаблоны и смотреть, что там понавводили в аннотациях.
  • Зависимость. Проект обрастает ещё одним инструментом, за которым нужно следить, обновлять, и который может в один прекрасный день сломаться. Доверия ебать ноль к таким вещам, но игра стоит свеч.

Короче, инструмент мощный, но не для слабонервных. Как скальпель хирурга — в умелых руках творит чудеса, а в руках идиота — одно сплошное увечье.