Triton/Documentation/ADR/ADR-002-layered-architecture-and-dependency-direction.md
Otávio 3e878667a1 Add Triton App
Signed-off-by: Otavio Cordeiro <otaviocc@users.noreply.github.com>
2025-12-15 20:39:07 +01:00

89 lines
4.2 KiB
Markdown

# ADR-002: Layered Architecture and Dependency Direction
**Status:** Accepted
**Date:** 2025-01-11
**Context:**
When designing the OMG application, I wanted to establish clear architectural boundaries that would prevent common issues like tight coupling, circular dependencies, and difficulty testing. I needed a structure that would:
1. Separate concerns cleanly (UI, business logic, data access)
2. Make dependencies explicit and enforceable
3. Enable testing at each layer in isolation
4. Prevent accidental violations of architectural rules
**Decision:**
I adopted a strict layered architecture with enforced one-way dependency flow. The layers are:
```
Views
View Models
Repositories
Network & Persistence Services
Shared Services (OMGAPI, SessionService, DesignSystem)
Foundation Modules (FoundationExtensions, Utilities)
```
**Dependency Rules (Enforced):**
1. **UI → Repository (NOT → Services):** Views and ViewModels depend on Repository protocols, never directly on NetworkService or PersistenceService
2. **Repository → Services:** Repositories coordinate between NetworkService and PersistenceService layers
3. **Services → Shared Utilities:** Services depend only on infrastructure (OMGAPI, SessionService) and utilities
4. **No upward dependencies:** Lower layers cannot import higher layers
5. **Cross-cutting packages independent:** Infrastructure packages (DesignSystem, OMGAPI) do not depend on features
**Layer Responsibilities:**
- **Views (SwiftUI):** Presentation logic only, delegating actions to ViewModels
- **ViewModels (@Observable):** UI state management, coordinating user actions via Repository protocols
- **Repositories:** Domain logic, caching strategies, data coordination between network and persistence
- **NetworkService:** API communication, mapping remote payloads to DTOs (OMGAPI models)
- **PersistenceService:** Swift Data storage, local data management with domain or DTO representations
- **Shared Infrastructure:** Cross-cutting concerns (HTTP client, session management, UI components)
- **Foundation Modules:** Pure utilities with no domain knowledge
**How Dependencies are Enforced:**
SPM package dependencies in `Package.swift` files make violations impossible at compile time. For example:
- A View's package can depend on Repository but not NetworkService
- NetworkService cannot import Repository (would be rejected by SPM)
- Repositories are often `actor` types, ensuring thread-safe data operations
**Consequences:**
### Positive
- **Testability:** Each layer can be tested independently using protocol mocks/stubs
- **Compile-time safety:** Architectural violations are caught by the Swift compiler
- **Clear responsibilities:** Each layer has a well-defined purpose
- **Flexibility:** Implementations can be swapped without affecting higher layers (e.g., switching persistence strategies)
- **Reasoning:** Easy to understand where code belongs and how data flows
- **Concurrency safety:** Actor isolation at repository layer prevents data races
### Negative
- **Initial complexity:** New features require thinking about multiple layers
- **Boilerplate:** Protocol definitions and implementations add code volume
- **Cross-layer changes:** Some features require touching multiple layers sequentially
### Neutral
- **Layer granularity:** Ongoing decisions about when to introduce intermediate layers (e.g., Service layer between Repository and UI)
**Related Decisions:**
- [ADR-001: Modular Architecture with Swift Package Manager](ADR-001-modular-architecture-with-spm.md) - SPM enables enforcement
- [ADR-003: Feature-Based Package Organization](ADR-003-feature-based-package-organization.md) - How layers map to package targets
- [ADR-009: Protocol-First Repository and Service Boundaries](../Patterns/ADR-009-protocol-first-boundaries.md) - Testing and abstraction approach
- [ADR-012: DTO-Based Data Flow](../Data-Flow/ADR-012-dto-based-data-flow.md) - How data transforms across layers
**Notes:**
This strict layering was designed from the start to prevent architectural erosion over time. The one-way dependency flow ensures the codebase remains maintainable as it grows.