DEV Community

Sebastien Lato
Sebastien Lato

Posted on

SwiftUI Dependency Graph Visualization & Auditing (Enforce Architecture, Don’t Trust It)

Every large SwiftUI codebase eventually says:

“We follow clean architecture.”

Then six months later:

  • features import each other
  • ViewModels talk to services directly
  • infrastructure leaks upward
  • cycles appear
  • nobody knows what depends on what

Architecture without enforcement always decays.

This post shows how to design dependency graph visualization & auditing for SwiftUI apps so your architecture is:

  • visible
  • enforceable
  • reviewable
  • resilient over time

🧠 The Core Principle

Architecture is a graph — not a guideline.

If you can’t see your dependency graph, you can’t control it.


🧱 1. Define Allowed Dependency Directions

Before tooling, define rules.

Example:

Views
→ ViewModels
→ Domain
→ Infrastructure

Rules:

  • no upward dependencies
  • no cross-feature imports
  • infrastructure never imports features
  • features never import each other directly

Write this down. This is your contract.


🧬 2. Treat Modules as Graph Nodes

Each logical module is a node:

  • Feature modules
  • Domain modules
  • Infrastructure modules
  • Shared utilities

The graph edges are imports.

This means:

  • imports = architectural dependencies
  • build errors = enforcement points

🔍 3. Generate the Dependency Graph

Use static analysis to extract imports.

Example approaches:

  • Swift Package Manager manifests
  • Xcode build logs
  • custom SourceKit parsing
  • scripts that scan import statements

Output a graph format (DOT / JSON):

FeatureA → Domain
FeatureA → FeatureB ❌

Visualization exposes reality instantly.


🧭 4. Visualize the Graph

Render the graph using:

  • Graphviz
  • Mermaid
  • custom dashboards

You should be able to:

  • see cycles
  • spot illegal edges
  • identify hotspots
  • track growth over time

If architecture can’t be visualized, it can’t be trusted.


🧪 5. Automated Dependency Audits

Turn architecture rules into tests.

Example:

fail if Feature imports Infrastructure
fail if Feature imports Feature
fail if cycle detected
Enter fullscreen mode Exit fullscreen mode

Run audits:

  • locally
  • in CI
  • on every PR

Architecture violations should fail builds — not code reviews.


🧠 6. Ownership & Boundaries

Every node should have:

  • an owner
  • a purpose
  • allowed dependencies

When a dependency is added:

  • ask why
  • document it
  • review the boundary

Undefined ownership accelerates decay.


🔁 7. Detect Cycles Early

Cycles kill:

  • testability
  • refactors
  • parallel work

Graph tooling should detect:

  • direct cycles
  • transitive cycles
  • hidden cycles via shared utilities

Break cycles immediately — they only get worse.


⚠️ 8. Common Dependency Anti-Patterns

Avoid:

  • shared “Utils” modules that import everything
  • feature-to-feature imports
  • infrastructure leaking into ViewModels
  • global singletons as dependency shortcuts
  • “temporary” imports that stay forever

If it’s convenient, it’s probably wrong.


🧠 Mental Model

Think:

Architecture Rules
 → Dependency Graph
   → Automated Audits
     → Build Enforcement
Enter fullscreen mode Exit fullscreen mode

Not:

“Let’s try to remember the rules”


🚀 Final Thoughts

Dependency graph auditing gives you:

  • enforceable architecture
  • fearless refactoring
  • faster onboarding
  • safer scaling
  • long-lived codebases

Architecture is not documentation.
It is constraint + visibility.

Top comments (0)