Tuist를 활용한 기능단위 앱 개발

SeongHo Hong
9 min readApr 9, 2022

--

안녕하세요 iOS 개발자 홍성호 입니다. 지난번에 센드버드의 새로운 샘플 앱의 구조를 설계했었는데요. 지난 구조의 단점인 Feature App을 확장하기 어려운 점을 Tuist로 개선한 사례를 이야기해보려 합니다.

도입 이유

지난번에 설계한 샘플앱을 보면 FeatureApp을 추가할 때는 BasicApp을 복사해서 또 생성하는 구조로 만들어져 있습니다.

(지난글 그림 재활용 😇)

Feature App 별로 View의 자유도를 최대한 많이 주기 위해서 Basic App을 복붙하는 건데, 이러면 아래와 같이 xcproject 파일의 정보를 Rename 해줘야하는 번거로운 과정들이 있습니다… Feature App이 아마도 수십개 만들어질텐데, 이런 반복 작업들을 할 생각을 하니 너무 끔찍했어요 🤔 혼자 만드는거라면 저만의 불편함에서 그치겠지만 다른 개발자와 함께 샘플을 만드는거라서 이런 불편함을 그냥 두고 볼 수는 없었습니다.

이것만 하는게 아니라… Scheme도 수정하고, info.plist 경로도 맞춰주고, 외부 dependency도 한번 더 확인하고…

이 구조를 봤을 때 Tuist가 바로 떠올랐는데, 사용해본 적이 없었고 하나의 Workspace 아래에 App을 여러개 만드는 구조는 예시로 거의 없어서 망설이고 있었어요.

때마침 사이드 프로젝트를 빌드업하고 있어서 그 프로젝트에 Tuist를 간단히 적용해볼 수 있었습니다. 사이드 프로젝트로 진행중인 앱 이름도 변경될 가능성이 있는 아주 유동적인 상태였기 때문에 한번 써보기 좋았던 것 같아요.

역시 Tuist 하면… 민소네님 블로그와 강훈님 적용기를 꺼내보게 되는데요. 아래 글들을 읽으면서 용기를 한번 내고, 공식 문서를 열어보면서 입맛대로 수정하기 시작했어요.

적용하기

생각보다 공식문서가 아주 잘되어 있다고 느꼈어요. 필요한 것들을 하나씩 검색해서 찾을 수 있어서 좋았습니다.

모든 과정을 다 설명하면 좋겠지만, 저도 여러분도 지칠테니ㅎ 제가 주로 사용했던 명령어만 써보겠습니다.

  • Tuist manifests 수정하기: tuist edit
  • 외부 Dependency 불러오기: tuist fetch
  • xcworkspace/xcodeproj 파일 생성하기: tuist generate

Dependency.swift 통해서 외부 라이브러리를 로컬 폴더로 불러오는데 이걸 안하면 tuist generate 해도 라이브러리를 찾을 수 없는 상태가 됩니다. 저는 처음에 이것 때문에 약간 헤맸습니다 🥲

Workspace 하나에 여러 App을 연결하는 구조라서 저는 이런 식으로 Workspace.swift 파일을 만들었구요.

let workspace = Workspace.create()extension Workspace {

static func create() -> Workspace {
Workspace(
name: "Samples",
projects: [
"Apps/**",
"Modules/**+"
],
schemes: []
)
}

}

Apps 폴더 아래에 App Scheme을 두고, Modules 폴더 아래에 공통 로직 라이브러리를 뒀습니다.

Project.swift 파일은 이런식으로 되어 있어요.

import ProjectDescription
import ProjectDescriptionHelpers
let project = Project.app(name: "BasicGroupChannel")

뭐지 App 이름 밖에 없네? 싶을 수 있는데 Tuist 프로젝트 생성시에 만들어주는 ProjectDescriptionHelpers 공간을 그대로 활용해서 extension을 만들었습니다.

extension Project {

/// Helper function to create the Project for this ExampleApp
public static func app(name: String) -> Project {
Project(
name: name,
organizationName: "Sendbird",
targets: [
makeAppTarget(
name: name,
platform: .iOS,
dependencies: [
.project(
target: "CommonModule",
path: .relativeToRoot("Modules/CommonModule")
)
]
)
]
)
}
}

이렇게 해두면 또 다른 App을 추가로 생성할 때도 같은 내용으로 Project.app(name:)에 파라미터만 바꾸면 App을 간단히 추가할 수 있게 됩니다.

이렇게 Workspcae, Project의 설계도를 그려놓고서 tuist generate로 실제 프로젝트 파일을 생성하면 다음과 같이 깔끔한 구조의 프로젝트를 만날 수 있습니다. 👍👍👍

장점

이제는 복사하고 Rename 하는 번거로운 일 없이 간편하게 새로운 App을 추가할 수 있게 되었습니다. 아직 모든 샘플 앱이 완성된게 아니라서 public repo 상태는 아니지만 다른 개발자와 함께 협업할 때 굉장히 편하다는 느낌을 받았습니다.

협업할 때 모듈별로 Asset을 관리해주는게 은근 귀찮은데, CommonModuleAsset.yourAssetName.image 이런식으로 코드로 접근할 수 있도록 tuist가 extension을 만들어주는데 Asset을 그냥 String으로 불러오는 것보다 안전한 느낌이었어요.

서비스 앱에서는 xcworkspace, xcodeproj 파일이 git conflict 풀어주는게 진짜 귀찮고 경우에 따라서는 프로젝트 파일이 열리지 않아서 곤란한 경우가 있는데, .gitignore 에 아래와 같이 추가해두고

*.xcodeproj
*.xcworkspace

로컬에서는 tuist generate를 통해서 conflict 없는 프로젝트 파일을 사용할 수 있다는 것도 큰 장점입니다.

단점

단점이라고 하기엔 좀 애매하지만ㅋㅋ 누군가 주도해서 Tuist에 익숙해져야 하고, Workspace, Project, Dependency 파일을 만들어야 한다는 점이 걸림돌이 될 것 같아요.

규모 있는 프로젝트에서는 필수라고 느꼈고, 팀원이 적은 프로젝트에서는 어렵진 않지만 Tuist 설정 파일을 관리해줘야 하는 것 때문에 망설여질 것 같습니다. 그래도 원하면 언제든 Tuist를 걷어내도 문제 없는 구조라서 한번 써보는 것을 추천드립니다 🙂

추가팁: Github Action 🚀

App이 계속 추가되는 구조다 보니 기존 App Scheme들이 모두 빌드되는지 확인해야하는게 큰 불편함이라 생각되었어요ㅠ 실제로 작업 초반에 App을 2~3개 추가했는데 하나는 빌드 에러가 나는 것을 놓치는 경우가 발생했습니다.

다행히 로컬에서 tuist build 를 실행시키면 모든 스킴이 정상적으로 빌드되는지 확인할 수 있습니다! 이것도 좋지만 Github Action으로 PR이 올라오거나 머지될 때 마다 체크되면 좋겠다는 생각을 했어요.

https://docs.tuist.io/guides/continuous-integration/#github-actions

tuist를 위한 github action이 있어서 바로 사용해볼 수 있었습니다. 그런데 사용법 대로 했는데 자꾸 오류가 발생했어요… 😭 알고보니 tuist 최신 버전이 아직 반영되지 않았기 때문이었습니다. tuist local 3.0.1 을 통해서 버전이 담긴 .tuist-version 파일을 만들면 3.0.1 기준으로 작동해서 Github Action도 정상적으로 작동합니다.

그리고 깨알팁으로… 해당 Github Action에 대한 status badge를 만들 수 있는데 아래와 같이 접근하면 링크를 얻을 수 있어요.

이걸 README.md 에 넣어두면 프로젝트가 정상적으로 빌드되는지 쉽게 확인할 수 있습니다.

정리

초기 세팅 후에 몇 주가 지난 상태인데, 다른 분들과 협업하면서 Tuist를 도입하기 잘했다는 생각을 하고 있어요. 이 도구가 없었으면 프로젝트를 운영하는데 많은 어려움이 있었을 것 같습니다. 풀고 싶은 어려움을 써보고 싶었던 도구로 해결해서 즐거웠던 경험이었습니다. 다른 분들도 한번 도입해보면 좋겠네요! 혹시 작업한 Repo 궁금한 분들은 아래 링크에서 확인해주세요👇

--

--

SeongHo Hong

Software Engineer 🧑‍💻https://github.com/cozzin