- Use Swift Package Manager (SPM) as the source of truth for package structure and dependencies.
- Prefer
swift packageCLI commands for structural changes whenever the command exists. - Use
swift package add-dependencyto add dependencies instead of hand-editing package graphs. - Use
swift package add-targetto add library, executable, or test targets. - For package configuration not covered by CLI commands, update
Package.swiftintentionally and keep edits minimal. - Keep package graph updates together in the same change (
Package.swift,Package.resolved, and target/test layout when applicable). - Validate package changes with:
swift buildswift test
- Use idiomatic Swift and Cocoa-style naming conventions.
- Prefer explicit, consistent, and unambiguous names.
- Prefer compact and concise code; use shorthand syntax when readability remains high.
- Prefer trailing-closure syntax when it improves clarity.
- Avoid deep nesting; refactor into focused helpers and types.
- Prefer value types (
struct,enum) for domain modeling. - Prefer concrete types internally; use protocols at module seams and integration boundaries.
- Mark classes as
finalby default. - Prefer synthesized conformances (
Codable,Equatable,Hashable, etc.) where possible. - Prefer synthesized/memberwise initializers; avoid unnecessary custom initializers.
- Use enums as namespaces to group related concerns.
- Keep code modular and cohesive; group highly related concerns together.
- Avoid spaghetti code and tight coupling.
- Prefer pure Swift solutions where practical.
- Keep code compliant with Swift 6 language mode.
- Keep strict concurrency checking enabled.
- Use modern structured concurrency (
async/await, task groups) instead of legacy async patterns. - For app-facing packages, prefer approachable concurrency defaults with main-actor isolation by default.
- Introduce parallelism where it produces clear performance gains.
- Prefer
@Observationover Combine for observation/state propagation. - Prefer frameworks and packages from Swift.org, Swift on Server, Apple, and Apple Open Source ecosystems when suitable.
- Commonly acceptable examples include packages like
swift-algorithms.
- Use Swift Testing (
import Testing) as the default test framework. - Avoid XCTest unless an external constraint requires it.
- Keep formatting consistent with
swift-formatconventions. - Keep linting clean against
swiftlintwith clear, maintainable rule intent.
- Prefer
swift packagefor package-focused workflows (dependency graph, targets, manifest intent, and local package validation). - Prefer
swift packagesubcommands for structural package edits before manually editingPackage.swift. - Use
swift buildandswift testas the default first-pass validation commands. - Use
xcodebuildwhen validating Apple platform integration details thatswift packagedoes not cover well (schemes, destinations, SDK-specific behavior, and configuration-specific builds/tests). - Keep
xcodebuildinvocations explicit and reproducible (always pass scheme, destination or SDK, and configuration when relevant). - Prefer deterministic non-interactive CLI usage in automation/CI for both
swift packageandxcodebuild.