반응형

모듈화(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. 결론

모듈화는 단순히 “프로젝트 쪼개기”가 아닙니다.
빌드 시간 개선, 구조적 안정성, 테스트 용이성, 팀 협업 효율, 유지보수성을 획기적으로 향상시키는 실무 필수 설계 전략입니다

반응형
Posted by 까칠코더
,