mirror of
https://github.com/otaviocc/Triton.git
synced 2026-01-30 04:04:27 +00:00
59 lines
3.6 KiB
Markdown
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.
|