# Цена удобства {#the-cost-of-convenience}

**Разработка редактора кода, который мог бы использоваться в самых разных
проектах** - от небольших до крупных - является сложной задачей. Многие
инструменты решают эту задачу путем наслоения своих решений и обеспечения
расширяемости. Самый нижний слой очень низкоуровневый и близок к базовой системе
сборки, а самый верхний слой - это высокоуровневая абстракция, удобная в
использовании, но менее гибкая. Таким образом, они делают простые вещи простыми,
а все остальное - возможным.

Однако **[Apple](https://www.apple.com) решила использовать другой подход в
Xcode**. Причина неизвестна, но, скорее всего, оптимизация под задачи масштабных
проектов никогда не была их целью. Они сделали ставку на удобство для небольших
проектов, не обеспечили достаточной гибкости и сильно связали инструменты с
базовой системой сборки. Чтобы добиться удобства, они предоставили разумные
настройки по умолчанию, которые вы можете легко заменить, и добавили множество
неявных поведений, связанных со временем сборки, которые являются виновниками
многих проблем при масштабировании.

## Ясность и масштаб {#explicitness-and-scale}

При работе в масштабе **явность имеет ключевое значение**. Она позволяет системе
сборки заранее проанализировать и понять структуру проекта и зависимости, а
также выполнить оптимизацию, которая иначе была бы невозможна. Та же явность
критически важна для обеспечения надежной и предсказуемой работы таких функций
редактора, как [SwiftUI
previews](https://developer.apple.com/documentation/swiftui/previews-in-xcode)
или [Swift
Macros](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/macros/).
Поскольку Xcode и проекты Xcode приняли неявность допустимым дизайнерским
решением ради удобства – принцип, который унаследовал менеджер пакетов Swift, –
сложности работы с Xcode проявляются и в Swift Package Manager.

> [!NOTE]
> **The Role Of Tuist**
>
> Роль Tuist можно описать как инструмент, который предотвращает неявно
> определенные проекты и использует явность для обеспечения лучшего опыта
> разработчиков (например, валидация, оптимизация). Такие инструменты, как
> [Bazel](https://bazel.build), идут дальше, спускаясь на уровень системы сборки.


Этот вопрос почти не обсуждается в сообществе, но он очень важен. Работая над
Tuist, мы заметили, что многие организации и разработчики думают, что текущие
проблемы, с которыми они сталкиваются, будут решены с помощью [Swift Package
Manager](https://www.swift.org/documentation/package-manager/), но они не
понимают, что, поскольку он построен на тех же принципах, даже если он смягчает
так хорошо известные конфликты Git, они ухудшают опыт разработчиков в других
областях и продолжают делать проекты неоптимизируемыми.

В следующих разделах мы рассмотрим несколько реальных примеров того, как
неявность влияет на работу разработчика и здоровье проекта. Список не является
исчерпывающим, но он должен дать вам хорошее представление о проблемах, с
которыми вы можете столкнуться при работе с проектами Xcode или пакетами Swift.

## Когда удобство начинает мешать {#convenience-getting-in-your-way}

### Общий каталог созданных продуктов {#shared-built-products-directory}

Xcode использует каталог внутри Derived Data для каждого продукта. В нем
хранятся артефакты сборки, такие как скомпилированные двоичные файлы, файлы dSYM
и журналы. Поскольку все продукты проекта попадают в один и тот же каталог,
который по умолчанию виден другим таргетам для компоновки, **таргеты могут
неявно зависеть друг от друга.** Хотя это может не представлять проблемы при
наличии всего нескольких таргетов, при росте проекта это может проявиться в виде
неудачных сборок, которые трудно отладить.

Следствием этого проектного решения является то, что многие проекты случайно
собираются с плохо определенным графом зависимостей.

> [!TIP]
> **Tuist Detection Of Implicit Dependencies**
>
> Tuist предоставляет
> <LocalizedLink href="/guides/features/projects/inspect/implicit-dependencies">команду</LocalizedLink>
> для обнаружения неявных зависимостей. С её помощью можно проверять в CI, что все
> зависимости указаны явно.


### Поиск неявных зависимостей в схемах {#find-implicit-dependencies-in-schemes}

Определять и поддерживать граф зависимостей в Xcode становится все сложнее по
мере роста проекта. Это сложно, потому что зависимости зашиты в файлах
`.pbxproj` в виде фаз и настроек сборки, отсутствуют инструменты для
визуализации и работы с графом, а изменения в нём (например, добавление нового
динамического прекомпилированного фреймворка) могут потребовать изменений
конфигурации выше по цепочке (например, добавлениt новой фазы сборки для
копирования фреймворка в бандл).

В какой-то момент Apple решила, что вместо того, чтобы развивать графовую модель
до чего-то более управляемого, разумнее добавить опцию разрешения неявных
зависимостей во время сборки. Это опять же сомнительный выбор, поскольку в итоге
вы можете получить замедленное время сборки или непредсказуемые сборки.
Например, сборка может пройти локально из-за некоторого состояния в данных
derive, которые действуют как
[singleton](https://en.wikipedia.org/wiki/Singleton_pattern), но затем не
скомпилироваться на CI из-за другого состояния.

> [!TIP]
> Мы рекомендуем отключить эту функцию в схемах проекта и использовать, например,
> Tuist, который облегчает управление графом зависимостей.


### SwiftUI Previews и статические библиотеки/фреймворки {#swiftui-previews-and-static-librariesframeworks}

Некоторые функции редактора, такие как SwiftUI Previews или Swift Macros,
требуют компиляции графа зависимостей для редактируемого файла. Такая интеграция
редактора с системой сборки требует, чтобы система сборки разрешала все неявные
зависимости и формировала корректные артефакты, необходимые для работы этих
функций. Как можно представить, **чем более неявным является граф, тем сложнее
эта задача для системы сборки**, и поэтому неудивительно, что многие из этих
функций работают ненадёжно. Мы часто слышим от разработчиков, что они давно
перестали использовать SwiftUI Previews из-за их ненадёжности. Вместо этого они
либо используют примеры приложений, либо избегают определённых решений, таких
как статические библиотеки или скриптовые фазы сборки, поскольку они нарушают
работу этих функций.

### Сливаемые библиотеки {#mergeable-libraries}

Динамические фреймворки, хотя и более гибкие и удобные в работе, негативно
влияют на время запуска приложений. С другой стороны, статические библиотеки
запускаются быстрее, но увеличивают время компиляции и с ними сложнее работать,
особенно при сложных графах зависимостей. *Разве не было бы здорово, если бы
можно было переключаться между ними в зависимости от конфигурации?* Вероятно,
именно так подумала Apple, когда решила поработать над сливаемыми библиотеками.
Однако и здесь они снова перенесли ещё больше логики разрешения зависимостей на
этап сборки. Если вы рассуждаете о графе зависимостей, представьте, насколько
труднее это делать, когда статическая или динамическая природа таргера
определяется во время сборки на основе настроек в других таргетах. Удачи в
попытках обеспечить надёжную работу и при этом не сломать такие фичи, как
SwiftUI Previews.

**Многие пользователи приходят в Tuist, желая использовать сливаемые библиотеки,
и наш ответ всегда один и тот же: в этом нет необходимости.** Вы можете
управлять тем, будут ли ваши таргеты статическими или динамическими, на этапе
генерации, в результате чего получается проект с графом, известным ещё до
компиляции. При этом не требуется разрешать какие-либо переменные во время
сборки.

```bash
# The value of TUIST_DYNAMIC can be read from the project {#the-value-of-tuist_dynamic-can-be-read-from-the-project}
# to set the product as static or dynamic based on the value. {#to-set-the-product-as-static-or-dynamic-based-on-the-value}
TUIST_DYNAMIC=1 tuist generate
```

## Явно, явно и ещё раз явно {#explicit-explicit-and-explicit}

Если и существует важный неписаный принцип, который мы рекомендуем каждому
разработчику или организации, стремящимся к масштабируемой разработке в Xcode,
то он заключается в том, чтобы придерживаться явности. И если с явностью трудно
справиться в сырых проектах Xcode, стоит рассмотреть другие инструменты, либо о
[Tuist](https://tuist.io), либо о [Bazel](https://bazel.build). **Только в этом
случае становятся возможны надёжность, предсказуемость и оптимизации**

## Будущее {#future}

Сделает ли Apple что-то для предотвращения всех вышеперечисленных проблем,
неизвестно. Их постоянные решения, встроенные в Xcode и Swift Package Manager,
не дают оснований полагать, что это произойдёт. Как только вы разрешили неявную
конфигурацию как допустимое состояние, **трудно двигаться дальше, не внося
разрушительных изменений.** Возврат к первым принципам и переосмысление дизайна
инструментов может привести к поломке многих проектов Xcode, которые случайно
компилировались годами. Представьте себе, как взбунтуется сообщество, если это
произойдет.

Компания Apple оказалась перед проблемой курицы и яйца. Удобство – это то, что
помогает разработчикам быстро начать работу и создавать больше приложений для
своей экосистемы. Однако решения, направленные на обеспечение этого удобства в
масштабах, затрудняют гарантирование надёжной работы некоторых функций Xcode.

Поскольку будущее неизвестно, мы стараемся **быть как можно ближе к отраслевым
стандартам и проектам Xcode**. Мы предотвращаем описанные выше проблемы и
используем накопленные знания для обеспечения лучшего опыта разработчиков. В
идеале мы не должны прибегать к генерации проектов, но недостаточная
расширяемость Xcode и Swift Package Manager делают это единственным возможным
вариантом. К тому же это безопасный вариант, потому что для того, чтобы сломать
проекты Tuist, им придется сломать проекты Xcode.

В идеале **система сборки должна была бы быть более расширяемой**, но разве
хорошая идея – иметь плагины или расширения, которым приходится работать в мире
неявных конфигураций? Это не выглядит разумным решением. Поэтому, похоже, нам
по-прежнему понадобятся внешние инструменты вроде Tuist или
[Bazel](https://bazel.build), чтобы обеспечить лучший опыт разработчика. А может
быть, Apple однажды удивит нас всех и сделает Xcode более расширяемым и явным…

А до тех пор вам придётся выбирать: сделать ставку на удобство Xcode и принять
связанный с этим технический долг или довериться нам в этом пути к лучшему опыту
разработчика. Мы вас не разочаруем.
