본문 바로가기
프로젝트관리

Tuist Domain Layer - Domain 모듈 만들기

by zinozino 2025. 1. 12.

Tuist 프로젝트에서 도메인 레이어를 구성하는 방법에 대해 알아보겠습니다.

1. Domain Layer 정의하기

Domain Layer는 Interface, Implementation, Testing, Tests 타겟으로 구성되며,

Feature Layer와 Shared Layer 사이에 위치하여 도메인 로직을 관리합니다.

프로젝트 구조 설정

프로젝트에서 필요한 디렉토리 구조를 아래와 같이 생성합니다:

Manifests/
├── ProjectDescriptionHelpers/
│   └── DomainLayer.swift        # Domain Layer 설정을 위한 헬퍼 파일
└── Projects/
    └── Domain/
        └── User/                # 도메인 모듈 (예: User)
            ├── Interface/       # 인터페이스 정의
            ├── Sources/         # 실제 구현체
            ├── Testing/         # 테스트를 위한 Mock/Stub
            └── Tests/           # 단위 테스트
            └── Project.swift    # 프로젝트 설정 파일

DomainLayer 모듈 구현

DomainLayer.swift


import ProjectDescription

public func makeDomainLayer(name: String, targetDependency: [TargetDependency] = []) -> Project {
    
    let interfaceName = name + "Interface"
    let implementationName = name
    let testingTargetName = name + "Testing"
    let testTargetName = name + "Tests"
    
    // Interface 타겟 설정
    let interface = Target.target(name: interfaceName,
                                  destinations: .iOS,
                                  product: .framework,
                                  bundleId: AppConfiguration.baseBundleId + interfaceName,
                                  infoPlist:  .extendingDefault(with: ["ENABLE_TESTS": .boolean(true)]),
                                  sources: ["Interface/**"]
                                  
                                  
    )
    
    // Implementation 타겟 설정
    let implementation = Target.target(name: implementationName,
                                       destinations: .iOS,
                                       product: .staticFramework,
                                       bundleId: AppConfiguration.baseBundleId + implementationName,
                                       infoPlist:  .extendingDefault(with: ["ENABLE_TESTS": .boolean(true)]),
                                       sources: ["Sources/**"],
                                       dependencies: [
                                        .target(name: interfaceName)
                                       ] + targetDependency
                                       
    )
    
    // Testing 타겟 설정
    let testing = Target.target(name: testingTargetName,
                                destinations: .iOS,
                                product: .framework,
                                bundleId: AppConfiguration.baseBundleId + testingTargetName,
                                infoPlist:  .extendingDefault(with: ["ENABLE_TESTS": .boolean(true)]),
                                sources: ["Testing/**"],
                                dependencies: [
                                 .target(name: interfaceName)
                                ]
                              
    )
    // Tests 타겟 설정
    let test = Target.target(name: testTargetName,
                             destinations: .iOS,
                             product: .unitTests,
                             bundleId: AppConfiguration.baseBundleId + testTargetName,
                             infoPlist:  .extendingDefault(with: ["ENABLE_TESTS": .boolean(true)]),
                             sources: ["Tests/**"],
                             dependencies: [
                                .target(name: testingTargetName),
                                .target(name: implementationName)
                             ]
                           
 )
    
    let settings = makeSettings(name: name)
    let scheme = makeScheme(name: name)
    
    return Project(name: name,
                   organizationName: AppConfiguration.baseBundleId,
                   packages: [],
                   settings: settings,
                   targets: [
                    interface,
                    implementation,
                    testing,
                    test
                   ]
                   ,schemes: [scheme]
    )
    
}

User 도메인 프로젝트 설정

Project.swift

import ProjectDescription
import ProjectDescriptionHelpers

let project = makeDomainLayer(name: "User")

이렇게 설계한 이유

Domain Layer 계층의 특징

  • Testing 타겟을 통한 테스트 더블(Mock, Stub) 제공
  • 도메인 로직의 독립적인 테스트 환경 구성

모듈 구성

  • TMA(Tuist에서 권장하는 The Modular Architecture)를 활용
  • Interface: 도메인의 인터페이스 정의
  • Sources: 실제 도메인 로직 구현
  • Testing: 테스트를 위한 Mock/Stub 객체 제공
  • Tests: 도메인 로직 검증을 위한 단위 테스트

의존성 관리

  • Interface를 통한 도메인 간 의존성 관리
  • Testing을 통한 테스트 코드 재사용성 확보
  • Implementation의 구체적인 의존성 은닉