Mejores prácticas
A lo largo de los años trabajando con diferentes equipos y proyectos, hemos identificado un conjunto de mejores prácticas que recomendamos seguir al trabajar con Tuist y proyectos de Xcode. Estas prácticas no son obligatorias, pero pueden ayudarte a estructurar tus proyectos de una manera que facilite su mantenimiento y escalabilidad.
Xcode#
Patrones desaconsejados#
Configuraciones para modelar entornos remotos#
Muchas organizaciones utilizan configuraciones de compilación para modelar diferentes entornos remotos (por ejemplo, Debug-Production o Release-Canary), pero este enfoque tiene algunas desventajas:
- Inconsistencias: Si hay inconsistencias de configuración en todo el grafo, el sistema de compilación podría terminar usando la configuración incorrecta para algunos targets.
- Complejidad: Los proyectos pueden terminar con una larga lista de configuraciones locales y entornos remotos difíciles de comprender y mantener.
Las configuraciones de compilación se diseñaron para reflejar diferentes ajustes de compilación, y los proyectos rara vez necesitan más que solo Debug y Release. La necesidad de modelar diferentes entornos se puede lograr de otra manera:
- En compilaciones Debug: Puedes incluir todas las configuraciones que deberían ser accesibles durante el desarrollo en la app (por ejemplo, endpoints) y cambiarlas en tiempo de ejecución. El cambio puede realizarse mediante variables de entorno de lanzamiento del scheme o con una interfaz dentro de la app.
- En compilaciones Release: En caso de una release, puedes incluir únicamente la configuración a la que está vinculada la compilación de release y no incluir la lógica en tiempo de ejecución para cambiar configuraciones mediante directivas del compilador.
Aunque Tuist admite configuraciones no estándar y facilita su gestión en comparación con los proyectos vanilla de Xcode, recibirás advertencias si las configuraciones no son consistentes en todo el grafo de dependencias. Esto ayuda a garantizar la fiabilidad de la compilación y evita problemas relacionados con la configuración.
Proyectos generados#
Carpetas compilables#
Tuist 4.62.0 añadió soporte para carpetas compilables (grupos sincronizados de Xcode), una característica introducida en Xcode 16 para reducir conflictos de fusión.
Aunque los patrones comodín de Tuist (por ejemplo, Sources/**/*.swift) ya eliminan los conflictos de fusión en proyectos generados, las carpetas compilables ofrecen beneficios adicionales:
- Sincronización automática: La estructura de tu proyecto se mantiene sincronizada con el sistema de archivos; no es necesario regenerar al añadir o eliminar archivos
- Flujos de trabajo compatibles con IA: Los asistentes y agentes de programación pueden modificar tu base de código sin desencadenar la regeneración del proyecto
- Configuración más sencilla: Define rutas de carpeta en lugar de gestionar listas explícitas de archivos
Recomendamos adoptar carpetas compilables en lugar de los atributos tradicionales Target.sources y Target.resources para una experiencia de desarrollo más ágil.
let target = Target(
name: "App",
buildableFolders: ["App/Sources", "App/Resources"]
)
let target = Target(
name: "App",
sources: ["App/Sources/**"],
resources: ["App/Resources/**"]
)
Dependencias#
Forzar versiones resueltas en CI#
Al instalar dependencias de Swift Package Manager en CI, recomendamos usar la bandera --force-resolved-versions para garantizar compilaciones deterministas:
tuist install --force-resolved-versions
Esta bandera garantiza que las dependencias se resuelvan utilizando las versiones exactas fijadas en Package.resolved, eliminando problemas causados por la no determinismo en la resolución de dependencias. Esto es especialmente importante en CI, donde las compilaciones reproducibles son críticas.
Instalación de dependencias en caché en GitHub Actions#
Para proyectos generados, usa tuist/install para instalar las dependencias fijadas en Package.resolved y almacenarlas en caché entre ejecuciones. Utiliza automáticamente volúmenes de caché en Tuist Runners y la caché de GitHub en otros runners.
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
Para un proyecto en un subdirectorio, pasa su ruta relativa al checkout:
- uses: tuist/install@v1
with:
path: apps/ios
Consulta la referencia de la acción para ver opciones adicionales.
Programación con agentes y worktrees#
Los agentes de programación y los colaboradores humanos trabajan cada vez más en paralelo: un desarrollador mantiene abierto un worktree para la funcionalidad que está revisando mientras uno o más agentes iteran en sus propias ramas en worktrees hermanos. Algunas decisiones de proyecto facilitan mucho este proceso.
Usa carpetas compilables para ediciones impulsadas por agentes#
Cuando un agente añade o elimina archivos, cualquier cosa que dependa de una lista de archivos en Project.swift requiere tuist generate antes de que el proyecto vuelva a compilarse. Las carpetas compilables transfieren esa responsabilidad a los grupos sincronizados de Xcode, por lo que las ediciones en el árbol de archivos ya no desencadenan una regeneración.
Combina esto con la generated-projects habilidad, que enseña a los agentes el flujo de trabajo diario de un proyecto Tuist.
No aísles la caché por worktree#
Tuist sigue la especificación de directorios base XDG, por lo que, de forma predeterminada, todos los worktrees en la misma máquina comparten ~/.cache/tuist y ~/.local/state/tuist. Esto es lo que deseas: los helpers compilados en un worktree, los plugins descargados en otro y los binarios del caché de módulos obtenidos por un tercero son todos reutilizables.
Las invocaciones concurrentes de tuist entre worktrees son seguras para ejecutar en paralelo. Evita apuntar TUIST_XDG_CACHE_HOME a una ruta local del worktree a menos que necesites específicamente aislamiento; hacerlo obliga a cada worktree a recalentar helpers, plugins y binarios.
Mantén el directorio temporal de SwiftPM por worktree#
Swift Package Manager tiene sus propios controles de ruta. --scratch-path es un estado de trabajo mutable y por defecto es .build, mientras que --cache-path es el directorio de caché compartido. Esas dos rutas no deben tratarse igual cuando hay varios worktrees activos.
El comportamiento predeterminado de tuist install ya mantiene el directorio temporal de SwiftPM bajo el directorio del paquete, por lo que cada worktree obtiene su propio .build. Mantén ese aislamiento. Un único directorio temporal compartido de SwiftPM puede mezclar checkouts, intermedios de compilación, plugins, macros y archivos de bloqueo de ramas no relacionadas.
Si pasas argumentos de SwiftPM a través de tuist install -- ... o mediante installOptions en Tuist.swift, comparte --cache-path cuando quieras obtener dependencias más rápido, pero deja --scratch-path sin establecer o apúntalo a un directorio local del worktree:
import ProjectDescription
let tuist = Tuist(
project: .tuist(
installOptions: .options(
passthroughSwiftPackageManagerArguments: [
"--cache-path",
"/Users/Shared/swiftpm/cache/xcode-16-macos",
]
)
)
)
Usa una variable de entorno de contenedor o de CI para la ruta de la caché si necesita variar según Xcode, la toolchain de Swift o la plataforma. Evita confirmar un --scratch-path compartido en el repositorio.
Si el estado de las dependencias parece corrupto solo en un worktree, elimina el directorio .build de ese worktree y ejecuta tuist install de nuevo. Si la caché compartida de SwiftPM parece sospechosa entre worktrees, usa swift package purge-cache antes de volver a instalar las dependencias.
Apóyate en la caché de módulos#
El caché de módulos es lo que hace viables los worktrees paralelos. Dado que Tuist calcula un hash determinista para cada objetivo, dos worktrees que apuntan a ramas que comparten la mayor parte de su historial utilizarán los mismos binarios. Ejecuta tuist cache en cada commit a main desde CI; localmente, tuist generate en cada worktree obtiene todo lo posible desde la caché y solo compila lo que tu rama ha cambiado realmente.
Si un worktree recurre a compilaciones desde el código fuente cuando esperabas un acierto de caché, sigue los pasos de depuración del hashing; los hashes no deterministas (causados normalmente por rutas absolutas en el proyecto) son la causa más común y se manifiestan claramente al comparar dos worktrees.
Acelera la resolución de paquetes Swift con el registro#
Cada worktree resuelve los paquetes Swift de forma independiente. En un proyecto con un grafo de dependencias grande, esto suma rápidamente. Cambiar al Registro de Tuist evita volver a clonar los historiales de git y reduce la resolución de minutos a segundos.
Da a los agentes acceso a las métricas del proyecto#
Una vez que las compilaciones y los tests se ejecutan en muchos worktrees, lo más útil que puede hacer un agente es razonar sobre cuáles de esas ejecuciones han regresado, qué tests son inestables o cómo ha cambiado el tamaño del bundle. Tuist expone esos datos a través del servidor MCP y del paquete Skills. Elige uno por flujo de trabajo y mantente con él; mezclar ambos para la misma tarea suele producir un comportamiento inconsistente en los agentes.