← All topics/Architecture & design patterns

Question 7

Refactoring a massive view controller

A 4,000-line view controller handles networking, analytics, and SwiftData. What incremental refactor plan would you present?

Follow-ups

  • How do you avoid breaking QA during the migration?

Answer outline

Don't rewrite the whole controller at once. Use a strangler refactor that keeps the screen working while you move one responsibility out at a time, in this order:

  1. 1.Extract dependencies: move networking, analytics, and SwiftData access behind small injected services, so the controller talks to protocols instead of owning the work.
  2. 2.Extract state: move the screen logic (loading state, user actions, formatting, validation, and save commands) into a view model.
  3. 3.Thin the controller: what is left owns lifecycle, binding, and navigation wiring, and nothing else.

Keep each pull request small enough to review and ship on its own. When a step is risky, protect it with tests, a feature flag, or a side-by-side debug comparison against the old code path.

Principles

  • Work in order: extract dependencies, then extract state, then thin the controller.
  • Avoid big-bang rewrites, and ship one responsibility per pull request so each step is easy to review and easy to revert.
  • Keep ModelContext and other persistence details out of the view controller entirely.
  • After each extraction, check for retain cycles in the closures and delegates you just introduced.

Follow-up angles

  • Capture the current behavior in tests or snapshots before you start, then cover the states you touch at each step: loading, success, error, editing, saving, and navigation.