# Рекомендации {#best-practices}

За годы работы с различными командами и проектами мы выявили набор рекомендаций, которых советуем придерживаться при работе с Tuist и проектами Xcode. Эти рекомендации не являются обязательными, но они помогут структурировать проекты так, чтобы их было проще поддерживать и масштабировать.

## Xcode {#xcode}

### Нежелательные подходы {#discouraged-patterns}

#### Конфигурации для моделирования удалённых сред {#configurations-to-model-remote-environments}

Многие организации используют конфигурации сборки для моделирования различных удалённых сред (например, `Debug-Production` или `Release-Canary`), но у такого подхода есть недостатки:

- **Несогласованность:** Если в графе зависимостей есть несоответствия конфигураций, система сборки может использовать неверную конфигурацию для некоторых целей.
- **Сложность:** В проектах может накопиться длинный список локальных конфигураций и удалённых сред, которые трудно анализировать и поддерживать.

Конфигурации сборки предназначены для хранения различных настроек сборки, и проектам редко требуется больше, чем просто `Debug` и `Release`. Потребность в моделировании разных сред можно решить иначе:

- **В сборках Debug:** Вы можете включить в приложение все конфигурации, доступные при разработке (например, конечные точки), и переключать их во время выполнения. Переключение можно реализовать через переменные среды запуска схемы или через интерфейс внутри приложения.
- **В сборках Release:** Для релиза можно включить только ту конфигурацию, к которой привязана сборка, и исключить логику переключения конфигураций во время выполнения с помощью директив компилятора.

> [!NOTE]
> **Нестандартные конфигурации**
>
> Хотя Tuist поддерживает нестандартные конфигурации и упрощает их управление по сравнению с обычными проектами Xcode, вы получите предупреждения, если конфигурации не согласованы в графе зависимостей. Это помогает обеспечить надёжность сборки и предотвращает проблемы, связанные с конфигурациями.


## Сгенерированные проекты

### Папки сборки

Tuist 4.62.0 добавил поддержку **папок сборки** (синхронизированных групп Xcode) — функции, появившейся в Xcode 16 для уменьшения конфликтов при слиянии.

Хотя шаблоны с подстановочными знаками в Tuist (например, `Sources/**/*.swift`) уже устраняют конфликты слияния в сгенерированных проектах, папки сборки дают дополнительные преимущества:

- **Автоматическая синхронизация**: структура проекта остаётся синхронизированной с файловой системой — не нужно перегенерировать проект при добавлении или удалении файлов
- **Рабочие процессы, удобные для ИИ**: помощники и агенты могут изменять кодовую базу без запуска перегенерации проекта
- **Более простая настройка**: задавайте пути к папкам вместо управления явными списками файлов

Мы рекомендуем использовать папки сборки вместо традиционных атрибутов `Target.sources` и `Target.resources` для более эффективного процесса разработки.

::: code-group

```swift [With buildable folders]
let target = Target(
  name: "App",
  buildableFolders: ["App/Sources", "App/Resources"]
)
```

```swift [Without buildable folders]
let target = Target(
  name: "App",
  sources: ["App/Sources/**"],
  resources: ["App/Resources/**"]
)
```
<!-- -->
:::

### Зависимости

#### Фиксация разрешённых версий на CI

При установке зависимостей Swift Package Manager на CI мы рекомендуем использовать флаг `--force-resolved-versions` для обеспечения детерминированных сборок:

```bash
tuist install --force-resolved-versions
```

Этот флаг гарантирует, что зависимости разрешаются с использованием точных версий, зафиксированных в `Package.resolved`, что исключает проблемы, вызванные недетерминизмом при разрешении зависимостей. Это особенно важно на CI, где критична воспроизводимость сборок.

#### Кэшированная установка зависимостей в GitHub Actions {#dependency-cache-volumes}

Для сгенерированных проектов используйте [tuist/install](https://github.com/tuist/install) для установки зависимостей, зафиксированных в `Package.resolved`, и их кэширования между запусками. Он автоматически использует <.localized_link href="/guides/features/runners/cache-volumes">тома кэша</.localized_link> на Tuist Runners и кэш GitHub на других раннерах.

```yaml
name: Generate project
on:
  push:
    branches: [main]
  pull_request:

permissions:
  contents: read

jobs:
  generate:
    runs-on: tuist-macos
    steps:
      - uses: actions/checkout@v4
      - uses: jdx/mise-action@v4
      - uses: tuist/install@v1
      - run: tuist generate --no-open
```

Для проекта в подкаталоге укажите путь относительно 체크아웃нутого репозитория:

```yaml
- uses: tuist/install@v1
  with:
    path: apps/ios
```

См. [справочник по действию](https://github.com/tuist/install#usage) для дополнительных параметров.

### Разработка с агентами и рабочие деревья {#agentic-coding-and-worktrees}

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

#### Используйте папки сборки для изменений, выполняемых агентом {#worktrees-buildable-folders}

Когда агент добавляет или удаляет файлы, всё, что зависит от списка файлов в `Project.swift`, требует выполнения `tuist generate` перед повторной сборкой проекта. [Папки сборки](#buildable-folders) переносят эту ответственность на синхронизированные группы Xcode, поэтому изменения в дереве файлов больше не вызывают перегенерацию.

Совместите это с `generated-projects` <.localized_link href="/guides/features/agentic-coding/skills">навыком</.localized_link>, который обучает агентов повседневным рабочим процессам проекта Tuist.

#### Не изолируйте кэш для каждого рабочего дерева {#worktrees-shared-cache}

Tuist следует <.localized_link href="/cli/directories">спецификации базовых каталогов XDG</.localized_link>, поэтому по умолчанию все рабочие деревья на одной машине совместно используют `~/.cache/tuist` и `~/.local/state/tuist`. Это именно то, что нужно: хелперы, скомпилированные в одном рабочем дереве, плагины, загруженные в другом, и бинарные файлы из кэша модулей, полученные третьим, — все они повторно используемы.

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

#### Сохраняйте временные данные SwiftPM отдельно для каждого рабочего дерева {#worktrees-swiftpm-scratch}

Swift Package Manager имеет собственные механизмы управления путями. `--scratch-path` — это изменяемое рабочее состояние, по умолчанию равное `.build`, а `--cache-path` — общая директория кэша. Эти два пути не следует обрабатывать одинаково, когда активно несколько рабочих деревьев.

Поведение `tuist install` по умолчанию в Tuist уже хранит временные данные SwiftPM в директории пакета, поэтому каждое рабочее дерево получает собственный `.build`. Сохраняйте эту изоляцию. Одна общая директория временных данных SwiftPM может смешивать клоны, промежуточные результаты сборки, плагины, макросы и файлы блокировок из несвязанных веток.

Если вы передаете аргументы SwiftPM через `tuist install -- ...` или через `installOptions` в `Tuist.swift`, используйте общий `--cache-path`, если хотите ускорить загрузку зависимостей, но оставьте `--scratch-path` незаданным или укажите путь, локальный для рабочего дерева:

```swift
import ProjectDescription

let tuist = Tuist(
    project: .tuist(
        installOptions: .options(
            passthroughSwiftPackageManagerArguments: [
                "--cache-path",
                "/Users/Shared/swiftpm/cache/xcode-16-macos",
            ]
        )
    )
)
```

Используйте обертку или переменную окружения CI для пути к кэшу, если он должен различаться в зависимости от Xcode, инструментария Swift или платформы. Не добавляйте в репозиторий общий `--scratch-path`.

Если состояние зависимостей выглядит поврежденным только в одном рабочем дереве, удалите директорию `.build` этого рабочего дерева и снова запустите `tuist install`. Если общий кэш SwiftPM вызывает подозрения во всех рабочих деревьях, используйте `swift package purge-cache` перед повторной установкой зависимостей.

#### Опирайтесь на кэш модулей {#worktrees-module-cache}

<.localized_link href="/guides/features/cache/module-cache">Кэш модулей</.localized_link> делает параллельную работу с рабочими деревьями управляемой. Поскольку Tuist вычисляет детерминированный <.localized_link href="/guides/features/projects/hashing">хеш</.localized_link> для каждой цели, два рабочих дерева, указывающие на ветки с общей историей, будут использовать одни и те же бинарные файлы. Запускайте `tuist cache` при каждом коммите в `main` из CI; локально `tuist generate` в каждом рабочем дереве загружает из кэша всё возможное и собирает только то, что действительно изменилось в вашей ветке.

Если рабочее дерево возвращается к сборке из исходного кода, когда вы ожидали попадания в кэш, следуйте <.localized_link href="/guides/features/projects/hashing#debugging">шагам отладки хеширования</.localized_link>; недетерминированные хеши (обычно вызванные абсолютными путями в проекте) являются наиболее частой причиной, и они явно проявляются при сравнении двух рабочих деревьев.

#### Ускорьте разрешение Swift-пакетов с помощью реестра {#worktrees-registry}

Каждое рабочее дерево разрешает Swift-пакеты независимо. В проекте с большим графом зависимостей это быстро накапливается. Переход на <.localized_link href="/guides/features/package-registries/swift">Реестр Tuist</.localized_link> позволяет избежать повторного клонирования git-историй и сокращает время разрешения с минут до секунд.

#### Предоставьте агентам доступ к аналитике проекта {#worktrees-mcp}

Когда сборки и тесты запускаются во многих рабочих деревьях, самое полезное, что может сделать агент, — это определить, *какие* из этих запусков показали регрессию, какие тесты нестабильны или как изменился размер бандла. Tuist предоставляет эти данные через <.localized_link href="/guides/features/agentic-coding/mcp">MCP-сервер</.localized_link> и пакет <.localized_link href="/guides/features/agentic-coding/skills">Skills</.localized_link>. Выберите один вариант для каждого рабочего процесса и придерживайтесь его; смешивание обоих для одной задачи часто приводит к непоследовательному поведению агента.
