Skip to content
AgileLogics
5 min read

Code Organization and Style Tools

Prerequisites: Swift Package Manager, Access control

As a project grows, a consistent structure and automatic style checks keep it readable.

Organizing files

  • One main type per file, named after it: Cart.swift holds struct Cart.
  • Group by feature, not by kind. Checkout/, Profile/, and Search/ folders — each with its own models, views, and logic — scale better than one giant Models/ and one giant Views/ folder.
  • Use extensions to divide a type into sections, typically one per protocol conformance, marked with // MARK: - comments that Xcode shows in its jump bar:
struct Invoice {
    let lines: [Double]
}

// MARK: - Totals

extension Invoice {
    var subtotal: Double { lines.reduce(0, +) }
}

// MARK: - CustomStringConvertible

extension Invoice: CustomStringConvertible {
    var description: String { "Invoice(\(lines.count) lines)" }
}
  • Split into modules as the project grows: Swift package targets for networking, models, and features let each part build and be tested on its own, and access control between modules enforces boundaries.

Formatting: swift-format

swift-format (from the Swift project, included with Swift 6 toolchains) formats code consistently:

swift format --in-place --recursive Sources Tests

Xcode can also re-indent a selection with Ctrl + I.

Linting: SwiftLint

SwiftLint checks for style issues and common mistakes — force unwrapping, overly long functions, unused code:

Sources/Shop/Cart.swift:14:22: warning: Force Unwrapping Violation: Force unwrapping should be avoided (force_unwrapping)

Rules are configured in a .swiftlint.yml file. Running the formatter and linter in your editor and in CI means style never has to be argued about in code review.

Common mistakes

  • Views with hundreds of lines of mixed UI and business logic. Move logic into separate types that can be tested.
  • Disabling every lint rule that complains. Read why the rule exists first — many point to real bugs.