Swift House Style (Best Practices)
When writing or editing Swift, follow these rules unless the user explicitly requests otherwise.
Core principles
- Prefer clarity over cleverness. Optimize for the next reader.
- Keep functions small and single-purpose; aim for < 40 lines.
- Make illegal states unrepresentable: use enums, value types, and non-optional properties where possible.
- Prefer immutability:
letfirst; mutate in tight scopes only. - Favor composition over inheritance.
- Avoid deprecated platform APIs when a supported modern replacement exists for the project’s deployment targets.
- Prefer updating call sites to the current API shape during touched work rather than introducing new usages of deprecated APIs.
Naming & API design
- Use Swift API Design Guidelines: names should form grammatical phrases at call sites.
- Avoid abbreviations unless universally known (URL, ID, JSON).
- Prefer argument labels that clarify intent:
add(item:),move(from:to:). - Avoid boolean parameter traps (
doThing(true)). Prefer enums or clearly labeled parameters.
Optionals & error handling
- Avoid optional-chaining pyramids. Use
guard letto unwrap early. - Avoid force unwrap (
!) except in tests or truly impossible cases, with a comment. - Prefer
throwsfor recoverable failures; useResultwhen you must store/compose outcomes. - Define error types (
enum FooError: Error) with meaningful cases.
Control flow
- Prefer early exits with
guard. - Avoid deeply nested
ifs; extract functions or useswitch. - Prefer
switchfor enums; include adefaultonly when forward compatibility is required and justified.
Types, protocols, and generics
- Use protocols to model capabilities, not buckets of unrelated methods.
- Prefer generic constraints that are minimal and readable.
- Avoid over-engineering with generics; if a simple concrete type is clearer, choose clarity.
Value vs reference
- Prefer structs for models and pure data.
- Use classes for shared mutable identity or when required by frameworks.
- If using classes, document ownership and mutation expectations.
Concurrency Style
- Prefer Swift concurrency APIs over DispatchQueue. For main-thread hops, use
await MainActor.run { ... }orTask { @MainActor in ... }instead ofDispatchQueue.main.async, unless you are bridging a legacy API that specifically requires GCD.
Performance & memory
- Avoid unnecessary allocations in hot paths; otherwise, write clear code first.
- Use
lazyonly when it measurably helps or prevents expensive work. - Be careful with capturing
selfin escaping closures; prefer[weak self]where appropriate.
Documentation & comments
- Comments should explain why, not what.
- Use doc comments for public APIs and non-obvious behavior.
- Keep TODOs actionable and owned (include context, not just “fix later”).
File Organization
- Keep one primary view model type per source file.
- Do not define a view model inside a view file or inside another view model file.
- Keep SwiftUI views in their own files unless the nested view is private, tiny, and only meaningful as an implementation detail of the parent view.
- Feature-level views and view models should live under that feature’s folder, for example:
Timeline/Settings/Views/SettingsView.swiftTimeline/Settings/ViewModels/SettingsViewModel.swift
Review checklist output
When asked to review/refactor Swift code, produce:
- Issues found (grouped: correctness, concurrency, style, performance)
- Suggested diff or rewritten code
- Brief rationale per change