이전에는 Swift Package를 활용해 모듈화를 구현해 봤다면, 오늘은 Tuist를 활용해 모듈화 아키텍처 구조를 설계해보려고 한다.

먼저 Tuist에 대해서 아주 간략하게 개념을 잡고 가자면, 협업을 하면서 프로젝트 파일이 충돌되는 일이 잦아 conflict가 나는 일이 있다. 그 문제를 해결하는데 혼이 쏙 빠진 적이 있는데 이 프로젝트의 복잡한 설정과 관리를 코드로 처리할 수 있도록 도와주는 도구라고 이해하면 된다!
Swift 언어로 프로젝트를 관리하게 되니 여러 측면에서 생산성이 증가하고 이 외에도 모듈화 하는 과정에서 그 구조를 체계적이고 시각화할 수 있다는 점 등등 협업 하는 과정에서 아주 이점이 많은 툴이다.
이제 Tuist로 프로젝트를 시작해보자. 일단 Tuist가 설치되어있다는 것을 가정하고 바로 적용하는 것 부터 들어가보면
tuist init

프로젝트 터미널 루트에 상단과 같이 tuist init 명령어를 실행시키면 Tuist에서 제공하는 기본 매니페스트 파일과 기본 템플릿을 생성해준다. 사진과 같이 원하는 옵션을 선택해 다음 다음을 넘어가면 계정을 인증하라고 나오고 Tuist 계정을 인증하게되면 프로젝트 생성은 끝이 난다.

처음 파일이 만들어지면 사진과 같이 이런 구조가 생성되게 된다. 여기서 핵심은 Project.swift 파일인데 이 파일은 Xcode 프로젝트의 타겟, 의존성, 빌드 설정 등 Swift 코드로 선언하게 해주는 역할을 담당한다.
그리고 터미널에
tuist edit
을 입력하면 매니페스트 파일인 Project.swift 파일이 열리게 되는데 이 매니페스트 파일은 코드 가반으로 프로젝트를 선언할 수 있게 해주고, 한 파일 내에 여러 타겟을 선언해 서로 간의 의존성을 명시할 수 있게 해준다.
처음 매니페스트 파일로 들어가 Project를 확인해보면 현재 만들어진 프로젝트가 이렇게 사진과 같이 확인된다.

여기서 추가할 모듈들을 타겟 지정해 주게 되고 변경 사항이 생겼을때 Command + S를 눌러 저장 후 다시
tuist genarate
를 명령어 입력하게 되면 변경된 내용을 바탕으로 Tuist 에서 Workspace를 만들어 열어준다.

이 워크스페이스가 열리면 매니페스트 파일에서 수정했던 내용이 자동으로 반영되어 타겟 설정이 자동으로 되어있는 것을 볼 수 있다.
이런 방식으로 프로젝트 파일이 변경될때마다 최신화 하게 되면서 프로젝트를 관리할 수 있게 된다.
워크 플로우를 바탕으로 다시 설명해보자면
도메인, 뷰 등 추가 모듈을 만들고 싶으면 프로젝트 내 새로운 폴더를 만들고 관련 소스 파일을 추가한다. 그 다음 매니페스트 파일로 이동해 새로운 Target를 추가하고, 새로운 모듈의 소스 경로와 의존성을 정의해준다.
그 이후 tuist generate를 실행하면, 새로운 모듈이 추가된 프로젝트 파일이 열리게 된다!
이 과정을 바탕으로 아주 간단한 예제를 한번 살펴보자
먼저 프로젝트 파일이 이렇게 열린 것으로 시작하자면 Domain모듈을 만들어 데이터 모델을 설정해주고 이 모델이 App에서 import 되어 실행되는 과정을 해볼 예정
import Foundation
public struct UserModel: Codable, Identifiable, Equatable {
public let id: UUID
public let name: String
public let email: String
public init(id: UUID = .init(), name: String, email: String) {
self.id = id
self.name = name
self.email = email
}
public func isValidEmail() -> Bool {
let emailRegex = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\\\.[A-Za-z]{2,}"
let predicate = NSPredicate(format: "SELF MATCHES %@", emailRegex)
return predicate.evaluate(with: self.email)
}
}
Domain 레이어에서 유저 정보와 이메일을 입력받을 수 있도록 임의로 넣어준 뒤 매니페스트로 이동하자
이동하게 되면 Project에 알맞은 타겟을 지정해줘야 해당 모듈을 인식해 import 후 사용할 수 있게 되므로 의존성을 추가해주면 된다.
let project = Project(
name: "Tuist-Study",
targets: [
.target(
name: "Tuist-Study",
destinations: .iOS,
product: .app,
bundleId: "io.tuist.Tuist-Study",
infoPlist: .extendingDefault(
with: [
"UILaunchScreen": [
"UIColorName": "",
"UIImageName": "",
],
]
),
sources: ["Tuist-Study/Sources/**"],
resources: ["Tuist-Study/Resources/**"],
dependencies: [
.target(name: "Domain")
]
),
dependencies: [
.target(name: "Domain")
]
이와 같이 디펜던시 부분에 사용할 모듈을 설정해준 뒤 저장 후 tuist generate를 통해 xcode 프로젝트 파일을 업데이트 해주면

타겟에 자동으로 들어와있다.
import SwiftUI
import Domain
public struct ContentView: View {
let domainService = DomainService()
let users: [UserModel]
init() {
let fetched = domainService.fetchUsers()
self.users = domainService.validUsers(from: fetched)
}
public var body: some View {
VStack(spacing: 10) {
Text("Valid Users:")
.font(.headline)
ForEach(users, id: \\.id) { user in
Text("\\(user.name) (\\(user.email))")
}
}
.padding()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
App단의 ContentView에서 해당 도메인을 가져와 임포트 후 사용이 가능하게 된다. 이러한 방식으로 Tuist를 통한 모듈화가 진행되는 것 같다.

아직 Tuist의 많은 기능을 다 알아보진 못했지만 이렇게 모듈화가 진행된다는 점을 좀 이해한 것 같다 아직은 좀 어렵지만 그래도 계속 써보면서 익히는 수밖에!!
'◽️ Programming > iOS' 카테고리의 다른 글
| Tuist를 사용하면서 만난 Duplicate Symbol Error (0) | 2025.04.30 |
|---|---|
| Tuist Scaffold로 모듈 생성 자동화 하기 + 외부 Dependencies 추가하기 (0) | 2025.04.22 |
| 에러 핸들링과 Toast Message 활용하기 (0) | 2025.04.02 |
| Static Dispatch, Dynamic Dispatch (2/2) (0) | 2025.03.04 |
| Static Dispatch & Dynamic Dispatch (1/2) (0) | 2025.02.28 |