다크 모드
코딩 컨벤션
파일 구조 컨벤션
Feature 모듈 디렉토리 구조
Feature 모듈은 2가지 구조 중 하나를 따릅니다. Feature의 규모와 성격에 따라 선택합니다.
화면 수가 많고 공유 ViewModel이 필요한 경우:
Features/{FeatureName}/
Project.swift -- Tuist 프로젝트 정의
Sources/
Assembly/ -- Swinject Assembly
{FeatureName}Assembly.swift
PresentationSources/ -- 공유 ViewModel / Manager / Model
{Feature}ViewModel.swift
Managers/ -- Feature 전용 Manager/Helper
Model/ -- Presentation Model
UISources/ -- SwiftUI View (화면별 하위 디렉토리)
{Screen}/
{Screen}Builder.swift
{Screen}View.swift
{Screen}ViewModel.swift -- 화면 전용 ViewModel
Protocols/ -- Feature 내부 Protocol
Resources/ -- Feature 전용 리소스
Tests/ -- Unit TestViewModel은 PresentationSources/와 UISources/{Screen}/ 두 곳에 모두 존재할 수 있습니다. 여러 화면에서 공유하는 ViewModel은 PresentationSources/에, 특정 화면 전용 ViewModel은 해당 화면 디렉토리에 배치합니다.
화면 단위 파일 구성
하나의 화면은 최소 3개의 파일로 구성됩니다:
| 파일 | 역할 |
|---|---|
{Screen}Builder.swift | Builder 프로토콜 + 구현체 + Dependency 구조체 + UIHostingController 서브클래스 |
{Screen}View.swift | SwiftUI View |
{Screen}ViewModel.swift | ViewModel (PresentationSources/ 또는 해당 화면 디렉토리에 위치) |
네이밍 컨벤션
파일 네이밍
| 유형 | 패턴 | 예시 |
|---|---|---|
| SwiftUI View | {Screen}View.swift | HomeView.swift, LoopMainView.swift |
| ViewModel | {Screen}ViewModel.swift | HomeViewModel.swift |
| Builder | {Screen}Builder.swift | HomeBuilder.swift |
| API Target | {Domain}API.swift | AuthAPI.swift, HomeAPI.swift |
| Repository Protocol | {Domain}Repository.swift | AuthRepository.swift |
| DataSource Impl | {Domain}DataSourceImpl.swift | AuthDataSourceImpl.swift |
| Request DTO | {Action}Request.swift | LoginRequest.swift |
| Response DTO | {Action}Response.swift | LoginResponse.swift |
| Assembly | {Module}Assembly.swift | HomeAssembly.swift |
| Entity | {ModelName}.swift | User.swift, Loop.swift |
| Extension | {Type}+ext.swift | String+ext.swift, Date+ext.swift |
Protocol 네이밍
| 유형 | 패턴 | 예시 |
|---|---|---|
| Builder Protocol | {Screen}Buildable | HomeBuildable |
| Repository Protocol | {Domain}Repository | HomeRepository |
| UseCase Protocol | {Action}UseCase | AccountUseCase |
| Manager Protocol | {Domain}Manager | ContactManager |
구현체 네이밍
| 유형 | 패턴 | 예시 |
|---|---|---|
| UseCase Impl | {Action}UseCaseImpl | AccountUseCaseImpl |
| DataSource Impl | {Domain}DataSourceImpl | AuthDataSourceImpl |
| Manager Impl | {Domain}ManagerImpl | ContactManagerImpl |
아키텍처 컨벤션
MVVM 패턴 규칙
- ViewModel은
ObservableObject를 채택하고@Published프로퍼티를 통해 상태를 노출 - View는
@StateObject또는@ObservedObject로 ViewModel을 관찰 - ViewModel에서 View로의 데이터 흐름은 단방향
- ViewModel은 Domain 레이어에 주로 의존하지만, UIKit/SwiftUI import도 필요에 따라 허용
Dependency Injection 규칙
- 모든 의존성은 생성자 주입 (Constructor Injection) 사용
- Builder의 Dependency 구조체에 필요한 의존성 명시
- Protocol 기반 의존성 주입 (구체 타입 직접 주입 금지)
레이어 의존성 규칙
허용: Feature --> Domain --> (없음)
허용: Feature --> Repository (Assembly에서만)
허용: Repository --> Domain, Networking
금지: Domain --> Repository, Networking, Feature
금지: Feature A --> Feature B (Interface 모듈 통해서만)다국어(Localization)
| 언어 | 코드 | 파일 |
|---|---|---|
| 영어 | en | en.lproj/Localizable.strings |
| 한국어 | ko | ko.lproj/Localizable.strings |
| 일본어 | ja | ja.lproj/Localizable.strings |
코드 스타일
Swift 일반 규칙
guard let/guard구문을 early return에 활용async/await사용 (콜백 기반 코드 지양)enum의 associated value를 적극 활용 (API Target 등)- Access control을 명시적으로 지정 (
public,internal,private) final class사용 (상속이 필요 없는 경우)@unchecked Sendable은 Thread Safety가 보장되는 경우에만 사용
SwiftUI 규칙
- View body는 가능한 한 작게 유지
- 복잡한 뷰는 서브 뷰로 분리
- ViewModifier를 활용한 공통 스타일 적용 (DesignSystem 모듈)
- DesignSystem 모듈의 Semantic Color / Foundation Color 사용
변경 이력
| 날짜 | 내용 |
|---|---|
| 2026-03-10 | Feature 모듈 디렉토리 구조를 대형/소형 2가지 패턴으로 세분화, ViewModel 위치 규칙 수정 (PresentationSources + UISources 모두 가능), MVVM 규칙에서 UIKit/SwiftUI import 금지 조항 제거 (실제 코드 반영), Builder 파일 역할에 UIHostingController 서브클래스 추가 |