Стоимость удобства
** Разработка редактора кода, который мог бы использоваться в самых разных проектах **- от небольших до крупных - является сложной задачей. Многие инструменты решают эту задачу путем наслоения своих решений и обеспечения расширяемости. Самый нижний слой очень низкоуровневый и близок к базовой системе сборки, а самый верхний слой - это высокоуровневая абстракция, удобная в использовании, но менее гибкая. Таким образом, они делают простые вещи простыми, а все остальное - возможным.
Однако Apple решила использовать другой подход в Xcode. Причина неизвестна, но, скорее всего, оптимизация под задачи масштабных проектов никогда не была их целью. Они сделали ставку на удобство для небольших проектов, не обеспечили достаточной гибкости и сильно связали инструменты с базовой системой сборки. Чтобы добиться удобства, они предоставили разумные настройки по умолчанию, которые вы можете легко заменить, и добавили множество неявных поведений, связанных со временем сборки, которые являются виновниками многих проблем при масштабировании.
Ясность и масштаб
При работе в масштабе явность имеет ключевое значение. Она позволяет системе сборки заранее проанализировать и понять структуру проекта и зависимости, а также выполнить оптимизацию, которая была бы невозможна в противном случае. Эта же явность является ключевой для обеспечения надежной и предсказуемой работы таких функций редактора, как SwiftUI previews или Swift Macros. Поскольку Xcode и проекты Xcode приняли неявность как оправданный выбор дизайна для достижения удобства - принцип, который унаследовал менеджер пакетов Swift, - трудности, связанные с использованием Xcode, также присутствуют в менеджере пакетов Swift.
::: инфо РОЛЬ ТУИСТА
Роль Tuist можно охарактеризовать как инструмент, предотвращающий неявное определение проектов и использующий явное определение для обеспечения лучшего опыта разработчика (например, валидация, оптимизация). Такие инструменты, как Bazel, идут дальше, спускаясь на уровень системы сборки.
:::
Этот вопрос почти не обсуждается в сообществе, но он очень важен. Работая над Tuist, мы заметили, что многие организации и разработчики думают, что текущие проблемы, с которыми они сталкиваются, будут решены с помощью Swift Package Manager, но они не понимают, что, поскольку он построен на тех же принципах, даже если он смягчает так хорошо известные конфликты Git, они ухудшают опыт разработчиков в других областях и продолжают делать проекты неоптимизируемыми.
В следующих разделах мы рассмотрим несколько реальных примеров того, как неявность влияет на работу разработчика и здоровье проекта. Список не является исчерпывающим, но он должен дать вам хорошее представление о проблемах, с которыми вы можете столкнуться при работе с проектами Xcode или пакетами Swift.
Удобство мешает вам
Общий каталог созданных продуктов
Xcode использует каталог внутри каталога производных данных для каждого продукта. В нем хранятся артефакты сборки, такие как скомпилированные двоичные файлы, файлы dSYM и журналы. Поскольку все продукты проекта попадают в один и тот же каталог, который по умолчанию виден другим целям для компоновки, может оказаться, что цели неявно зависят друг от друга. Хотя это может не представлять проблемы при наличии всего нескольких целей, при росте проекта это может проявиться в виде неудачных сборок, которые трудно отладить.
Следствием такого решения является то, что многие проекты случайно компилируются с графом, который не является хорошо определенным.
TUIST DETECTION OF IMPLICIT DEPENDENCIES
Tuist предоставляет
командудля обнаружения неявных зависимостей. Вы можете использовать эту команду для проверки в CI, что все ваши зависимости являются явными.
Поиск неявных зависимостей в схемах
Определять и поддерживать граф зависимостей в Xcode становится все сложнее по мере роста проекта. Сложно потому, что они кодируются в файлах .pbxproj в виде фаз сборки и параметров сборки, нет инструментов для визуализации и работы с графом, а изменения в графе (например, добавление нового динамического прекомпилированного фреймворка) могут потребовать изменения конфигурации выше по течению (например, добавление новой фазы сборки для копирования фреймворка в бандл).
В какой-то момент Apple решила, что вместо того, чтобы развивать графовую модель до чего-то более управляемого, разумнее добавить опцию разрешения неявных зависимостей во время сборки. Это опять же сомнительный выбор, поскольку в итоге вы можете получить замедленное время сборки или непредсказуемые сборки. Например, сборка может пройти локально из-за некоторого состояния в данных derive, которые действуют как singleton, но затем не скомпилироваться на CI из-за другого состояния.
TIP
Мы рекомендуем отключить эту функцию в схемах проекта и использовать, например, Tuist, который облегчает управление графом зависимостей.
Предварительные версии SwiftUI и статические библиотеки/фреймворки
Некоторые функции редактора, такие как SwiftUI Previews или Swift Macros, требуют компиляции графа зависимостей из редактируемого файла. Такая интеграция между редакторами требует, чтобы система сборки разрешила все неявности и вывела правильные артефакты, необходимые для работы этих функций. Как вы можете себе представить, чем более неявным является граф, тем сложнее задача для системы сборки, и поэтому неудивительно, что многие из этих функций не работают надежно. Мы часто слышим от разработчиков, что они давно перестали использовать предварительные версии SwiftUI из-за их ненадежности. Вместо этого они используют либо примеры приложений, либо избегают определенных вещей, таких как использование статических библиотек или скриптовых фаз сборки, потому что они приводят к поломке функции.
Объединяемые библиотеки
Динамические фреймворки, хотя и более гибкие и удобные в работе, негативно влияют на время запуска приложений. С другой стороны, статические библиотеки быстрее запускаются, но влияют на время компиляции и с ними немного сложнее работать, особенно в сценариях со сложной графикой. Разве не было бы здорово, если бы вы могли менять одно или другое в зависимости от конфигурации? Должно быть, именно об этом подумали в Apple, когда решили поработать над сливаемыми библиотеками. Но опять же, они перенесли больше выводов на время сборки. Если вы рассуждаете о графе зависимостей, представьте, что вам придется делать это, когда статическая или динамическая природа цели будет определяться во время сборки на основе некоторых настроек сборки в некоторых целях. Удачи вам в обеспечении надежной работы и гарантированного отсутствия поломок таких функций, как предварительные просмотры SwiftUI.
Многие пользователи приходят в 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Явный, явный и явный
Если и есть важный неписаный принцип, который мы рекомендуем каждому разработчику или организации, желающей, чтобы их разработка в Xcode масштабировалась, так это то, что они должны принять явность. И если с явностью трудно справиться в сырых проектах Xcode, им следует подумать о чем-то другом, либо о Tuist, либо о Bazel. Только тогда станут возможны надежность, предсказуемость и оптимизация.
Будущее
Сделает ли Apple что-то для предотвращения всех вышеперечисленных проблем, неизвестно. Их постоянные решения, встроенные в Xcode и менеджер пакетов Swift, не дают оснований полагать, что они это сделают. Как только вы разрешили неявную конфигурацию как допустимое состояние, трудно двигаться дальше, не внося разрушительных изменений. Возврат к первым принципам и переосмысление дизайна инструментов может привести к поломке многих проектов Xcode, которые случайно компилировались годами. Представьте себе, как взбунтуется сообщество, если это произойдет.
Компания Apple оказалась перед проблемой курицы и яйца. Удобство - это то, что помогает разработчикам быстро начать работу и создавать больше приложений для своей экосистемы. Но их решения сделать удобство работы в таких масштабах затрудняют обеспечение надежной работы некоторых функций Xcode.
Поскольку будущее неизвестно, мы стараемся быть как можно ближе к отраслевым стандартам и проектам Xcode. Мы предотвращаем вышеупомянутые проблемы и используем имеющиеся у нас знания для обеспечения лучшего опыта разработчиков. В идеале мы не должны прибегать к генерации проектов, но недостаточная расширяемость Xcode и менеджера пакетов Swift делают это единственным возможным вариантом. К тому же это безопасный вариант, потому что для того, чтобы сломать проекты Tuist, им придется сломать проекты Xcode.
В идеале, система сборки была более расширяемой, но не будет ли плохой идеей иметь плагины/расширения, которые заключают контракты с неявным миром? Это не кажется хорошей идеей. Так что, похоже, нам понадобятся внешние инструменты вроде Tuist или Bazel, чтобы обеспечить лучший опыт разработчика. Или, может быть, Apple удивит нас всех и сделает Xcode более расширяемым и явным...
А пока этого не произошло, вам придется выбирать, хотите ли вы принять удобство Xcode и взять на себя все связанные с ним обязательства, или довериться нам в этом путешествии, чтобы обеспечить лучший опыт разработчика. Мы вас не разочаруем.
