Triton/Documentation/ADR/ADR-001-modular-architecture-with-spm.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

59 lines
3.6 KiB
Markdown

# ADR-001: Modular Architecture with Swift Package Manager
**Status:** Accepted
**Date:** 2025-01-11
**Context:**
When designing the OMG application architecture, I wanted to establish a solid foundation that would support long-term maintainability and growth. I evaluated several approaches for structuring the codebase:
- **Workspace with multiple Xcode targets:** Traditional approach but requires manual dependency management
- **CocoaPods/Carthage frameworks:** Third-party dependency managers with additional tooling overhead
- **Swift Package Manager (SPM):** Native Swift solution with first-class Xcode integration
**Decision:**
I chose Swift Package Manager as the foundation for a modular architecture, organizing the codebase into discrete packages within a `Packages/` directory from the outset. Each package represents either a feature domain (Auth, Status, Account, etc.) or infrastructure concern (OMGAPI, DesignSystem, SessionService, etc.).
Key principles of this SPM-based architecture:
1. **Local packages:** All packages reside in `Packages/` directory within the repository, not as external dependencies
2. **Explicit dependencies:** Each `Package.swift` declares its dependencies, making relationships clear and enforceable
3. **Target-based layering:** Within packages, I use multiple targets (main module, Service, Repository, NetworkService, PersistenceService) to enforce layer boundaries
4. **Public API surfaces:** Packages expose only necessary APIs; internal implementation details remain private
5. **Independent testing:** Each package has its own test target, enabling isolated unit testing
6. **Shared utilities first:** Foundation packages (FoundationExtensions, Utilities) have no feature dependencies
**Consequences:**
### Positive
- **Faster incremental builds:** Xcode only rebuilds changed packages and their dependents
- **Clear dependency graph:** SPM enforces acyclic dependencies at compile time, preventing circular references
- **Better code organization:** Related code lives together in cohesive packages with clear purposes
- **Improved testability:** Individual packages can be tested in isolation without application overhead
- **Enforced architecture:** Package boundaries make it impossible to violate layering rules without explicit dependency changes
- **Native tooling:** SPM is built into Xcode and Swift, requiring no additional setup
- **Scalability:** The architecture naturally accommodates growth without major restructuring
### Negative
- **Initial setup overhead:** Creating package structure requires upfront planning before writing feature code
- **Xcode scheme proliferation:** Each package and target creates additional schemes (mitigated by hiding unnecessary schemes)
- **Cross-package refactoring:** Moving code between packages requires updating multiple `Package.swift` files
- **Build system quirks:** Occasional Xcode caching issues require clean builds or derived data deletion
### Neutral
- **Package granularity decisions:** Ongoing judgment calls about when to split or merge packages
- **Version management:** All packages version together with the main app (not independent versioning)
**Related Decisions:**
- [ADR-002: Layered Architecture and Dependency Direction](ADR-002-layered-architecture-and-dependency-direction.md) - Defines how packages relate to each other
- [ADR-003: Feature-Based Package Organization](ADR-003-feature-based-package-organization.md) - Details package internal structure
**Notes:**
This modular approach was chosen from the beginning to establish clear boundaries and maintainability patterns from day one.