swift-refactor
Swift/SwiftUI Refactor (Modular MVVM-C)
Comprehensive refactoring guide for migrating Swift/SwiftUI code to modular MVVM-C with local SPM package boundaries and App-target composition root wiring.
Mandated Architecture Stack
┌───────────────────────────────────────────────────────────────┐
│ App target: DependencyContainer, Coordinators, Route Shells │
├───────────────────────────────────────────────────────────────┤
│ Feature modules: View + ViewModel (Domain + DesignSystem deps)│
├───────────────────────────────────────────────────────────────┤
│ Data package: repositories, remote/local stores, sync, retry │
├───────────────────────────────────────────────────────────────┤
│ Domain package: models, repository/coordinator/error protocols │
└───────────────────────────────────────────────────────────────┘
Dependency Rule: Feature modules never import Data and never import sibling features.
Clinic Architecture Contract (iOS 26 / Swift 6.2)
All guidance in this skill assumes the clinic modular MVVM-C architecture:
- Feature modules import
Domain+DesignSystemonly (neverData, never sibling features) - App target is the convergence point and owns
DependencyContainer, concrete coordinators, and Route Shell wiring Domainstays pure Swift and defines models plus repository,*Coordinating,ErrorRouting, andAppErrorcontractsDataowns SwiftData/network/sync/retry/background I/O and implements Domain protocols- Read/write flow defaults to stale-while-revalidate reads and optimistic queued writes
- ViewModels call repository protocols directly (no default use-case/interactor layer)
When to Apply
Reference these guidelines when:
- Migrating from deprecated SwiftUI APIs (ObservableObject, NavigationView, old onChange)
- Restructuring state management to use @Observable ViewModels
- Adding @Equatable diffing to views for performance
- Decomposing large views into 10-node maximum bodies
- Refactoring navigation to coordinator + route shell pattern
- Refactoring to Domain/Data/Feature/App package boundaries
- Setting up dependency injection through
DependencyContainer - Improving list/collection scroll performance
- Replacing manual Task management with
.task(id:)and cancellable loading
Non-Negotiable Constraints (iOS 26 / Swift 6.2)
@ObservableViewModels/coordinators,ObservableObject/@PublishedneverNavigationStackis owned by App-target route shells and coordinators@Equatablemacro on every view,AnyViewnever- Domain defines repository/coordinator/error-routing protocols; no framework-coupled I/O
- No dedicated use-case/interactor layer; ViewModels call repository protocols directly
- Views never access repositories directly
Rule Categories by Priority
| Priority | Category | Impact | Prefix | Rules |
|---|---|---|---|---|
| 1 | View Identity & Diffing | CRITICAL | diff- |
4 |
| 2 | API Modernization | CRITICAL | api- |
7 |
| 3 | State Architecture | CRITICAL | state- |
6 |
| 4 | View Composition | HIGH | view- |
7 |
| 5 | Navigation & Coordination | HIGH | nav- |
5 |
| 6 | Layer Architecture | HIGH | layer- |
5 |
| 7 | Architecture Patterns | HIGH | arch- |
5 |
| 8 | Dependency Injection | MEDIUM-HIGH | di- |
2 |
| 9 | Type Safety & Protocols | MEDIUM-HIGH | type- |
4 |
| 10 | List & Collection Performance | MEDIUM | list- |
4 |
| 11 | Async & Data Flow | MEDIUM | data- |
3 |
| 12 | Swift Language Fundamentals | MEDIUM | swift- |
8 |
Quick Reference
1. View Identity & Diffing (CRITICAL)
diff-equatable-views- Add @Equatable macro to every SwiftUI viewdiff-closure-skip- Use @EquatableIgnored for closure propertiesdiff-identity-stability- Use stable O(1) identifiers in ForEachdiff-printchanges-debug- Use _printChanges() to diagnose re-renders
2. API Modernization (CRITICAL)
api-observable-macro- Migrate ObservableObject to @Observable macroapi-navigationstack-migration- Replace NavigationView with NavigationStackapi-onchange-signature- Migrate to new onChange signatureapi-environment-object-removal- Replace @EnvironmentObject with @Environmentapi-alert-confirmation-dialog- Migrate Alert to confirmationDialog APIapi-list-foreach-identifiable- Replace id: .self with Identifiable conformanceapi-toolbar-migration- Replace navigationBarItems with toolbar modifier
3. State Architecture (CRITICAL)
state-scope-minimization- Minimize state scope to nearest consumerstate-derived-over-stored- Use computed properties over redundant @Statestate-binding-extraction- Extract @Binding to isolate child re-rendersstate-remove-observation- Migrate @ObservedObject to @Observable trackingstate-onappear-to-task- Replace onAppear closures with .task modifierstate-stateobject-placement- Migrate @StateObject to @State with @Observable
4. View Composition (HIGH)
view-extract-subviews- Extract subviews for diffing checkpointsview-eliminate-anyview- Replace AnyView with @ViewBuilder or genericsview-computed-to-struct- Convert computed view properties to struct viewsview-modifier-extraction- Extract repeated modifiers into custom ViewModifiersview-conditional-content- Use Group or conditional modifiers over conditional viewsview-preference-keys- Replace callback closures with PreferenceKeyview-body-complexity- Reduce view body to maximum 10 nodes
5. Navigation & Coordination (HIGH)
nav-centralize-destinations- Refactor navigation to coordinator patternnav-value-based-links- Replace NavigationLink with coordinator routesnav-path-state-management- Use NavigationPath for programmatic navigationnav-split-view-adoption- Use NavigationSplitView for multi-column layoutsnav-sheet-item-pattern- Replace boolean sheet triggers with item binding
6. Layer Architecture (HIGH)
layer-dependency-rule- Extract domain layer with zero framework importslayer-usecase-protocol- Remove use-case/interactor layer; keep orchestration in ViewModel + repository protocolslayer-repository-protocol- Repository protocols in Domain, implementations in Datalayer-no-view-repository- Remove direct repository access from viewslayer-viewmodel-boundary- Refactor ViewModels to expose display-ready state only
7. Architecture Patterns (HIGH)
arch-viewmodel-elimination- Restructure inline state into @Observable ViewModelarch-protocol-dependencies- Extract protocol dependencies through ViewModel layerarch-environment-key-injection- Use Environment keys for service injectionarch-feature-module-extraction- Extract features into independent modulesarch-model-view-separation- Extract business logic into Domain models and repository-backed ViewModels
8. Dependency Injection (MEDIUM-HIGH)
di-container-composition- Compose dependency container at app rootdi-mock-testing- Add mock implementation for every protocol dependency
9. Type Safety & Protocols (MEDIUM-HIGH)
type-tagged-identifiers- Replace String IDs with tagged typestype-result-over-optionals- Use Result type over optional with error flagtype-phantom-types- Use phantom types for compile-time state machinestype-force-unwrap-elimination- Eliminate force unwraps with safe alternatives
10. List & Collection Performance (MEDIUM)
list-constant-viewcount- Ensure ForEach produces constant view count per elementlist-filter-in-model- Move filter/sort logic from ForEach into ViewModellist-lazy-stacks- Replace VStack/HStack with Lazy variants for unbounded contentlist-id-keypath- Provide explicit id keyPath — never rely on implicit identity
11. Async & Data Flow (MEDIUM)
data-task-modifier- Replace onAppear async work with .task modifierdata-error-loadable- Model loading states as enum instead of boolean flagsdata-cancellation- Use .task automatic cancellation — never manage Tasks manually
12. Swift Language Fundamentals (MEDIUM)
swift-let-vs-var- Use let for constants, var for variablesswift-structs-vs-classes- Prefer structs over classesswift-camel-case-naming- Use camelCase naming conventionswift-string-interpolation- Use string interpolation for dynamic textswift-functions-clear-names- Name functions and parameters for clarityswift-for-in-loops- Use for-in loops for collectionsswift-optionals- Handle optionals safely with unwrappingswift-closures- Use closures for inline functions
How to Use
Read individual reference files for detailed explanations and code examples:
- Section definitions - Category structure and impact levels
- Rule template - Template for adding new rules
Reference Files
| File | Description |
|---|---|
| references/_sections.md | Category definitions and ordering |
| assets/templates/_template.md | Template for new rules |
More from pproenca/dot-skills
zod
Zod schema validation best practices for type safety, parsing, and error handling. This skill should be used when defining z.object schemas, using z.string validations, safeParse, or z.infer. This skill does NOT cover React Hook Form integration patterns (use react-hook-form skill) or OpenAPI client generation (use orval skill).
2.0Kclean-architecture
Clean Architecture principles and best practices from Robert C. Martin's book. This skill should be used when designing software systems, reviewing code structure, or refactoring applications to achieve better separation of concerns. Triggers on tasks involving layers, boundaries, dependency direction, entities, use cases, or system architecture.
1.4Kemilkowal-animations
Emil Kowalski's animation best practices for web interfaces. Use when writing, reviewing, or implementing animations in React, CSS, or Framer Motion. Triggers on tasks involving transitions, easing, gestures, toasts, drawers, or motion.
918vitest
Vitest testing framework patterns for test setup, async testing, mocking with vi.*, snapshots, and test performance (formerly test-vitest). This skill should be used when writing or debugging Vitest tests. This skill does NOT cover TDD methodology (use test-tdd skill), API mocking with MSW (use test-msw skill), or Jest-specific APIs.
907typescript
This skill should be used when the user asks to "optimize TypeScript performance", "speed up tsc compilation", "configure tsconfig.json", "fix type errors", "improve async patterns", or encounters TS errors (TS2322, TS2339, "is not assignable to"). Also triggers on .ts, .tsx, .d.ts file work involving type definitions, module organization, or memory management. Does NOT cover TypeScript basics, framework-specific patterns, or testing.
821nuqs
nuqs (type-safe URL query state) best practices for Next.js applications. This skill should be used when writing, reviewing, or refactoring code that uses nuqs for URL state management. Triggers on tasks involving useQueryState, useQueryStates, search params, URL state, query parameters, nuqs parsers, or Next.js routing with state.
735