반응형
모듈화(Modularization)로 빌드 속도 최적화
1. 들어가며
iOS 프로젝트가 커질수록 빌드 시간은 기하급수적으로 증가합니다.
특히 다음 상황에서는 빌드 시간이 개발 속도에 치명적 영향을 줍니다.
- 파일 수 500개 이상
- 타사 SDK 다수 포함
- SwiftUI + UIKit 혼합
- 네트워크/도메인/뷰모델의 의존 관계 증가
- 팀원 5명 이상의 협업 환경
이 문제를 실질적으로 해결하는 방법이 모듈화(Modularization) 입니다.
2. 모듈화의 효과
2.1 빌드 시간 단축
- 변경된 모듈만 빌드 → 전체 빌드 불필요
- Clean Build 시에도 병렬 빌드로 시간 대폭 감소
2.2 개발 생산성 증가
- 모듈 단위로 테스트 가능
- PR 충돌 감소
- 기능 담당 간 코드 영향 최소화
2.3 유지보수 용이
- Layer 간 책임 명확해짐
- 팀별 역할 분리 가능 (디자인/로직/네트워크 등)
3. 이상적인 모듈 구조
실무 기준 가장 많이 사용하는 모듈 구조는 아래와 같습니다.
App
├── Presentation
│ ├── FeatureA
│ ├── FeatureB
│ ├── SharedUI
│ └── Resources
├── Domain
│ ├── Repositories
│ ├── Entities
│ └── UseCases
├── Data
│ ├── RepositoryImpl
│ ├── DTO
│ ├── Mapper
│ ├── Network
│ └── Persistence
└── Core
├── Utility
├── Extensions
├── Logger
└── Config
4. 각 모듈의 역할
4.1 Presentation
- SwiftUI / UIKit 화면
- ViewModel
- UI 상태 관리
- Feature(기능)별로 모듈 구분 가능
4.2 Domain
- UseCase
- Entity
- Repository Interface
- 앱의 비즈니스 규칙 담당
4.3 Data
- Repository 구현체
- DTO, Mapper
- API, CoreData, UserDefaults 처리
4.4 Core
- 공통 유틸
- Logger
- Analytics
- Extensions
5. Tuist 기반 모듈화 예시
Project.swift
import ProjectDescription
let project = Project(
name: "MyApp",
targets: [
.target(
name: "Presentation",
destinations: .iOS,
product: .framework,
bundleId: "com.myapp.presentation",
sources: ["Presentation/Sources/**"],
dependencies: [
.project(target: "Domain", path: "../Domain"),
.project(target: "Core", path: "../Core")
]
),
.target(
name: "Domain",
destinations: .iOS,
product: .framework,
bundleId: "com.myapp.domain",
sources: ["Domain/Sources/**"]
),
.target(
name: "Data",
destinations: .iOS,
product: .framework,
bundleId: "com.myapp.data",
sources: ["Data/Sources/**"],
dependencies: [
.project(target: "Domain", path: "../Domain")
]
),
.target(
name: "Core",
destinations: .iOS,
product: .framework,
bundleId: "com.myapp.core",
sources: ["Core/Sources/**"]
)
]
)
6. 모듈화 시 주의할 점
6.1 양방향 의존 금지
예:
- Presentation ↔ Data
- Domain ↔ Presentation
이렇게 되면 모듈화 의미가 없다.
6.2 Domain은 순수해야 한다
- Foundation 외 외부 라이브러리 금지
- UIKit, SwiftUI 금지
- Alamofire 금지
6.3 Data layer는 Domain Interface만 의존
Domain → Data는 절대 안 됨.
6.4 Feature 간 직접 참조 금지
공통 기능은 SharedUI 또는 Core에 배치해야 한다.
7. 모듈화 실패 사례 (실무에서 자주 발생)
❌ Domain에 Alamofire import
→ Domain은 플랫폼 독립적이어야 한다.
❌ Presentation에서 DTO 직접 접근
→ Layer 규칙 완전히 붕괴
❌ Core/Shared 모듈이 거대해짐
→ 모듈화 무의미해짐
→ 모든 공통 기능이 Core로 몰리면 Core가 거대한 쓰레기장이 됨
8. 모듈별 테스트 전략
Presentation
- Snapshot Testing
- UI Test
Domain
- Unit Test (UseCase 중심)
- Mock Repository 활용
Data
- Repository Test
- Mapping Test
- DTO decoding Test
9. 모듈화를 시작하는 실무 단계
1단계
- Core / Domain / Presentation 3개로 분리
2단계
- Data 모듈 분리
3단계
- Feature 단위 모듈화
4단계
- Tuist 활용하여 자동화
- XcodeGen → Tuist 전환 권장
10. 체크리스트
- Domain은 순수해야 한다
- Presentation은 Domain 외 의존 없음
- Data는 Domain Interface 의존
- Core는 UI/Domain/Data와 무관한 공통 기능
- Feature 간 의존 제거
- 양방향 참조 절대 금지
- Tuist 또는 SPM 기반 구조 추천
11. 결론
모듈화는 단순히 “프로젝트 쪼개기”가 아닙니다.
빌드 시간 개선, 구조적 안정성, 테스트 용이성, 팀 협업 효율, 유지보수성을 획기적으로 향상시키는 실무 필수 설계 전략입니다
반응형
'Dev Study > iOS' 카테고리의 다른 글
| 테스트 작성 (Unit Test + Snapshot Test) (0) | 2025.11.14 |
|---|---|
| 앱 시작 속도 개선(App Launch Optimization) (0) | 2025.11.14 |
| Transition / Animation 최적화 (0) | 2025.11.14 |
| AutoLayout — Hugging / Compression Resistance 이해하기 (0) | 2025.11.14 |
| 네트워크 계층 — DTO / Domain 분리 (0) | 2025.11.14 |
| Swift Concurrency — 구조적 동시성 완전 이해 (0) | 2025.11.14 |
| 메모리 누수 방지 — weak / unowned 정확히 사용하기 (0) | 2025.11.14 |
| UIKit ↔ SwiftUI 혼용 시 Life-Cycle 이해하기 (0) | 2025.11.14 |

