top of page

CFA Reference: Glossary and Prohibited Patterns

Formal CFA AI Toolkit for iOS Documentation · Reference 11 of 26

This page collects the CFA vocabulary used across the reference, then lists the prohibited patterns from the CFA specification. A review rejects or refactors any of them.

Definitions

  • AppModel: The composition root that creates and exposes the concrete Features.
  • Feature: The concrete @MainActor owner of business rules, domain data, operation state and errors.
  • Feature API: A Feature's own non-private members; never a separate protocol.
  • ViewModel: A dedicated, screen-owned @MainActor @Observable class.
  • Repository: A domain-language storage protocol and its actor implementation.
  • Change gate: The completion checklist every change must pass.
  • Completion record: The evidence recorded at the end of a change: navigator maps, feature and concurrency inventories, build and tests at the final commit, and a human architecture review.
  • Shared in-flight task: One retained Task that overlapping callers await, cleared in defer.
  • Workflow mode: new-product development or established-product maintenance, recorded once in the project's instructions.

Rules

  1. Reject business calculations, classifications, validation or filtering in a View.
  2. Reject reusable business rules in a ViewModel, and one ViewModel shared by multiple unique screens.
  3. Reject ViewModels stored by AppModel, a root ViewModel or another ViewModel, and Views receiving ViewModels, Features, AppModel or repositories.
  4. Reject ViewModels depending on the whole AppModel instead of the smallest coherent set of narrow feature APIs.
  5. Reject Features containing navigation, sheets, dialogs or screen names, and repositories imported directly by Views or ViewModels.
  6. Reject deep chains through the AppModel object graph, default live dependencies hidden in AppModel.init, and asynchronous side effects inside initialisers.
  7. Reject Task handles stored by a SwiftUI View, and unstructured Tasks whose lifespan or cancellation affects correctness but is not stored and managed.
  8. Reject vague lifecycle or action names such as start, begin, process and prepareForUse, and speculative folders, layers or abstractions.
  9. Reject @unchecked Sendable used as a compiler-warning escape hatch, and serialising independent work when the required behaviour is concurrent.
  10. Reject Combine observation where Observation is sufficient, competing copies of shared feature state in multiple ViewModels, and Feature APIs exposing directly mutable domain collections.
  11. Reject domain types placed under storage merely because they are persisted, swallowed business or persistence failures, and expensive or blocking work on the main actor.

Decision rules

  • When a review finds a prohibited pattern, refactor it before the change is called complete.
  • When a pattern is not listed but adds a second owner of state, treat it as prohibited.
  • When a name is vague, rename it for its work: refresh(), save(), retry().
  • When a term on this page is unclear in code, look up its reference page in the links below.

Example

The compiled snippet below shows the allowed alternative to two prohibited patterns: the Feature exposes habits as private(set), not a directly mutable collection, and the ViewModel holds a narrow Feature dependency instead of the whole AppModel.

Compiled example

import Observation

struct Habit: Sendable, Equatable {
    var name: String
}

@MainActor
@Observable
final class HabitsFeature {
    private(set) var habits: [Habit] = []

    func addHabit(_ habit: Habit) {
        habits.append(habit)
    }
}

@MainActor
@Observable
final class HabitsViewModel {
    private let habitsFeature: HabitsFeature

    init(habitsFeature: HabitsFeature) {
        self.habitsFeature = habitsFeature
    }

    var habitCount: Int { habitsFeature.habits.count }
}

Compiled with Swift 6 language mode and warnings treated as errors: type-checked on Swift 6.2 and built on Swift 6.4 (Linux toolchains, Foundation and Observation only).

Common mistakes

  • Reading the list as style advice. Each item is a review rejection.
  • Fixing a prohibited pattern by renaming it, for example turning a Manager into a Service with the same responsibilities.
  • Replacing @unchecked Sendable with nonisolated(unsafe), which is the same escape hatch.

Links

bottom of page