
모바일
Tuist
Xcode 프로젝트를 관리할 수 있는 툴이며 Swift 파일로 설정을 관리한다.
StackOverflow 질문 수: 18
Github Stars : ★ 4869
사용 기업

원티드랩

당근

카카오뱅크

하이퍼커넥트

29cm

우아한형제들

카카오페이

위대한상상

핀크

씨제이이엔엠

우아한형제들Tech

크몽
여기어때컴퍼니
10살 여기어때 iOS앱의 모듈화 여정
여기어때 iOS 앱은 2014년 국내 숙소 숙박 서비스로 시작하여 딱 10년째인 2024년 지금은 해외여행, 항공권, 공간대여, 티켓까지 다양한 서비스를 제공하는 복합 플랫폼으로 성장했습니다. 여기어때 프로젝트는 서비스의 성장과 함께 계속해서 덩치가 커져 현재 약 70만 라인의 소스코드로 이루어져 있습니다.대규모 프로젝트 여기어때 Tuist 도입앱의 규모가 증가하고 하나의 프로젝트 위에서 많은 인력이 동시에 개발하는 상황이 되면서 iOS 개발자들은 다음과 같은 문제를 겪게 됐습니다.xcodeproj 파일의 컨플릭 문제(iOS 개발자라면 깊게 공감하실 것 같습니다.)프로젝트의 빌드시간이 점점 오래 걸리기 시작함우선, xcodeproj파일의 컨플릭 문제부터 해결해야 합니다.iOS IDE인 Xcode가 다루는 xcodeproj파일은, 프로젝트에 속한 소스의 변경 사항이 저장되어 있는 형태여서, 소스코드 파일이 변경될 때 해당 변경 이력 부분에서 전부 컨플릭이 발생하는 구조입니다.컨플릭이 발생하면 당연히 프로젝트 자체가 안열리게 되구요..컨플릭이 많이 발생하게 되면 git Tool 자체가 종료되어버리기도 합니다…😇머지해보기 전까진 프로젝트 파일 내에 컨플릭이 얼마나 많이 발생할지 예측할 수 없고, 이를 해결할 방법론도 없어서 개발자들이 프로젝트가 정상화될 때까지 손으로 컨플릭을 고쳐야 했습니다. 이는 대규모 앱 개발에 정말 크리티컬한 이슈이기 때문에, 일정 규모 이상의 프로젝트를 운용하는 iOS 개발 조직에서는 통상 Tuist와 같은 서드파티 프로젝트 관리 솔루션을 사용합니다. Tuist는 xcodeproj파일 기반으로 프로젝트 내 구성요소들을 관리하는 기존의 형태를 뒤집어서, Tuist 설정값 및 프로젝트 내 구성요소들을 기반으로 xcodeproj파일을 생성해 주는 형태로 동작하기 때문에, xcodeproj 파일 내 컨플릭에서 벗어날 수 있습니다.여기어때 iOS 파트 역시 xcodeproj 파일 컨플릭 이슈를 해결하기 위해 약 3개월 동안 아래와 같은 과정을 거쳐 완전히 Tuist 기반으로 프로젝트가 관리되도록 변경했습니다.프로젝트 구조 분석폴더 구조 정리외부 종속성 툴을 SPM(Swift Package Manager)으로 전환앱에서 외부 라이브러리를 찾지 못해 생기는 런타임 앱 크래시 해결라이브러리 중복 복사로 인한 빌드 에러와 앱 오류 해결예측 못한 오류가 없는지 앱 전체 검증 진행그 결과 브랜치를 머지할 때마다 발생하는 xcodeproj 파일 컨플릭 이슈가 해결되어 개발 생산성과 안정성이 크게 향상됐습니다. Tuist를 성공적으로 도입하면서 iOS 개발 환경에서 브랜치를 병렬로 개발 진행하는데 큰 걸림돌이였던 xcodeproj 컨플릭에서 벗어나게 되었고, 모듈을 자유롭게 추가/삭제 할 수 있는 환경이 만들어졌습니다.다음으로는 빌드시간 단축을 위한 모듈 분리 작업을 알아보겠습니다. 이를 통해 모듈들의 역할을 명확하게 분담하고, 각 모듈간의 참조 구조를 명확하게 분리할 수 있습니다.모듈화를 왜 할까?최초의 여기어때 앱은 Obj-C로 개발되었
tuist
비바리퍼블리카
레고처럼 조립하는 토스 앱
이게 뭐냐고요?바로, 토스 iOS 앱의 코드량입니다.토스팀은 사용자에게 가치를 전달하기 위해 끊임없이 서비스를 개발해왔어요. 지금 토스 앱 안에는 수백 개의 서비스가 들어있습니다. 그렇게 성장해오는 동안, 토스 iOS 앱도 Swift 100만 줄이 넘는 거대한 프로젝트로 자라났습니다.이 글을 읽고 계신 iOS 개발자분들에게 질문을 드려볼게요.이렇게 프로젝트가 크고 복잡해지면 뭘 해야 할까요?앱을 하나의 큰 Xcode 프로젝트로 관리하는 대신, 여러 개의 작은 모듈로 나눕니다. 그리고 모듈 간의 적절한 구조를 설계하는 거죠.코드 베이스가 커지면, 모듈 분리도 점점 더 중요해지죠. 그래서 토스 iOS 챕터도 모듈화에 대한 많은 고민을 했는데요.이 글에서는, 저희가 어떻게 슈퍼 앱 토스의 모듈을 관리하고 있는지 살펴볼게요.먼저 기존 토스 앱의 구조를 알아봐야겠죠?기존 토스 앱은 가장 일반적인 계층 구조로 이루어져 있었어요. 책임과 역할에 따라 계층을 나눠 해당 계층에는 그에 맞는 모듈들이 위치하고, 하위 계층에 있는 모듈은 상위 계층에 있는 모듈을 의존할 수 없는 형태죠.공통적으로 쓰이는 유틸리티 모듈들이 모여있는 Foundation 계층.최종적으로 사용자에게 제공될 앱이 위치한 App 계층.이렇게 계층적으로만 모듈을 관리하고 있었어요.일반적인 계층 구조도 꽤 오랜 시간 잘 작동했습니다. 계층 안에서의 모듈 분리도 되어있었고요. 하위 계층의 모듈이라면 필요에 따라 가져다 활용할 수 있었죠.하지만 수년간 토스에는 정말 많은 서비스가 생겼습니다. 다시 말해 Feature 계층에 모듈들이 엄청나게 늘어났죠.그러다 보니 문제가 발생했습니다.단순히 모듈 수가 많아서는 아니었어요. 많은 서비스가 생겨나면서, 모듈 간의 의존성이 폭발적으로 늘어나는 게 문제였죠.하나의 서비스가 Feature 레이어의 여러 모듈을 활용하는 경우가 많이 생겼습니다. 결과적으로 같은 계층 내에 의존 관계가 복잡해졌고요.그러자 순환 참조와 같은 문제가 발생하기도 했어요. 전반적인 모듈 구조도 이해하기에 너무 어려워졌습니다.처음에는 계층 구조를 유지하면서 대응을 해봤어요. 공통 기능을 다시 묶어서 하위 계층의 모듈로 분리하거나, 새로운 계층을 추가하여 공통 모듈을 추가로 분리하는 방식도 시도했고요.그런데 이렇게 하다 보니 지나치게 많은 계층이 생겨났어요. 적절한 계층 및 모듈 분리의 기준을 세우기도 애매해지더라고요.Microfeatures 아키텍처는 Tuist가 소개한 모듈 구조예요. (Tuist는 iOS 프로젝트 관리 툴입니다.)크게 보면, Microfeatures 아키텍처는 아래와 같이 5개의 요소로 구성되어 있어요.Feature의 실제 기능이 구현된 코드가 위치한 모듈이에요.Feature에서 제공하는 기능에 대한 외부 인터페이스와 모델을 제공하는 모듈이에요.단위 테스트나 Example 앱에서 사용될 코드와 Mock 데이터 등을 제공하는 모듈이에요.단위 테스트, UI 테스트 등이 위치한 모듈이에요.Feature의 기능을 간단히 체험해 볼 수 있는 작은 앱이에요.그래서 이 요소들
tuist
줌인터넷
Tuist 도입부터 적용까지 알려ZUM요! (feat. 모듈화)
14 min to readTuist 도입부터 적용까지 알려ZUM요! (feat. 모듈화)안녕하세요 ZUM iOS개발자 김남수(Enes)입니다. ZUM에서는 Tuist를 어떻게 도입하게 되었는지, 어떻게 사용하고 있는지와 Tuist를 적용한 프로젝트를 개선한 경험을 공유하고자 합니다. 가이드 없이 맨땅에 시작한 Tuist와 모듈 아키텍쳐 학습을 기반으로 설계하고 개발한 경험을 공유하는 글이여서 부족한 부분이 있을 수 있습니다. 편하게 읽어주시면 감사하겠습니다 :)Tuist 란?Xcode 프로젝트 생성과 유지관리를 편리하게 하는 것을 목표로 하는 CLI 도구입니다.Project.swift 파일을 기반으로 프로젝트(.xcodeproj)를 생성해 줍니다.이 파일에 프로젝트의 설정값을 정의하면 프로젝트 생성 시 정의한 설정값으로 생성됩니다.이를 통해 프로젝트 설정값을 실수로 건드려서 일어날 에러를 방지할 수 있습니다.Tuist 도입사실 Tuist의 도입을 특별하게 시도한 것은 아니였습니다.제가 입사했을 때 이미 한 프로젝트에 사용 중이었습니다.다른 툴들도 있지만 자연스럽게 Tuist를 먼저 사용하게 됐습니다.Tuist를 학습하면서 느낀 편리한 점은 아래와 같습니다.1. xcodeproj 파일이 없다.프로젝트를 커맨드 명령어로 그때그때 생성해 주기 떄문에 github에 .xcodeproj 프로젝트를 올리지 않고 코드만 올립니다. 따라서 협업 시 쉽게 경험해 볼 수 있는 프로젝트 파일경로에 관한 git 충돌을 회피할 수 있습니다.2. 모듈화하기 편리하다.Project파일을 생성하고 프로젝트와 타겟을 만들어 주는 메서드를 정의해 두면 모듈 생성 시 호출만 해서 사용하면 모듈 셋팅이 금방 끝납니다.3. 프로젝트의 모듈 의존관계를 파악하기 쉽다.Tuist의 큰 장점 중 하나라고 생각합니다. 의존된 모듈을 찾아가지 않아도 명령어 하나면 이미지로 보기 쉽게 의존 그래프를 그려줍니다.4. swift언어를 이용해서 모듈과 프로젝트 설정을 정의할 수 있다.Tuist 모든 설정 파일을 정의할 땐 swift를 사용합니다.기존 프로젝트는 모듈화 없이 하나의 모듈에 모든 코드가 있었습니다.모듈화하여 빌드속도를 향상하고 협업의 능률을 올릴 수 있도록 개선할 수 있을 것 같다는 생각이 들었습니다.구조를 재설계했지만 이미 많은 개발이 이뤄진 프로젝트라 모든 구조를 수정하기에 아쉽게도 주어진 시간이 부족해서 실제로 적용하지 못했습니다.기존 프로젝트에 적용하지 못 한 채 남겨진 모듈화를 새 프로젝트에서는 제대로 적용해 보고 싶었습니다.처음부터 완벽하게 사용할 수 없는 기술이라고 생각하고, 모듈 아키텍처는 개발하며 개선할 부분이 보이면 수정될 수 있다는 마음을 갖고 시작했습니다.Tuist 사용스키마 적용프로젝트에서 Tuist를 어떻게 사용하는지 간단하게 알아보겠습니다.우선 프로젝트를 Tuist로 생성할 때 스키마를 선택합니다.TUIST_MODE = INHOUSE tuist generateTUIST_MODE라는 환경변수를 이용하여개발용, 사내배포용, 마켓배포용을 구분하여 환경을 다르
tuist
ios
당근
Tuist 를 활용해 확장 가능한 모듈 구조 만들기
배경앱의 규모가 커지면 커질수록 단일 프로젝트로 앱을 개발하기 점점 어려워집니다. 먼저 빌드 속도가 느려지고, 객체간 물리적 의존을 끊을 수 없기 때문에 설계가 오염되는 경우가 많습니다.물리적 의존이란?모듈이 분리되지 않으면, 객체간 접근이 물리적으로 제한되는 것이 아니기에, 객체를 오용하기 쉽습니다. (개인의 의지에 따라 코드를 작성할 수 있다)ex) 추상화된 객체가 구체적인 구현체를 알게되는 상황당근마켓에서는 위 문제를 해결하기 위해 앱 프로젝트를 수많은 모듈로 분리했고, 이를 쉽게 관리하기 위해 Tuist 라는 도구를 활용하고 있습니다.당근마켓) XcodeGen 에서 Tuist 로 전환하기기준 없이 모듈을 분리만 한다면, 프로젝트의 구조는 더 복잡해지고 얻을 수 이점이 줄어듭니다.최근, 모듈 분리를 처음 시도하는 분들을 위해 당근마켓의 앱을 관통하는 Modular Architecture 에 대해 소개했습니다.MVVM, MVI 등 흔히 이야기되는 Presentation Layer 아키텍처와 다른 개념입니다.https://medium.com/media/17a1a4c9b817a6cd5a58500f7eda216f/href발표 내용을 짧게 요약해보면..역할에 따라 모듈 계층을 나눠 설계합니다.계층에는 Feature, Domain, Core, Shared 가 존재합니다.새로운 모듈을 추가할 때 모듈의 역할에 따라 적절한 계층을 지정하고, 인터페이스와 구현체를 분리할지 판단합니다.위 아키텍처를 토대로 당근마켓 프로젝트는 수십개의 모듈에서 수백개의 모듈로 분리되었고, 점차 기존의 방식으로 Xcode 프로젝트를 관리하기 어려워졌습니다.이번 글에서는 당근마켓에서 Tuist 를 활용해 어떻게 Xcode 프로젝트 관리 경험을 개선했는지 소개합니다.모듈이 많아지며 생기는 문제모듈의 수가 점차 늘어나면서 Tuist 에서 기본적으로 제공하는 인터페이스만으로는 프로젝트 관리에 어려움이 발생했습니다.별도의 개선 없이 Tuist 를 사용하면 수백개의 프로젝트 의존성이 존재하더라도, 이를 String 타입에 의존해 모듈을 추가하고 의존성을 구성하게 됩니다.이 때 엔지니어들은 프로젝트 구성에 어려움을 느낄 수 있고, 실수가 발생하기 쉽습니다.구체적인 예시로 살펴보겠습니다.// Project.swiftTarget( name: "FooFeature", platform: .iOS, product: .framework, bundleId: "com.featrues.foo", infoPlist: .default, sources: "Sources", dependencies: [ // 의존성을 String 기반으로 추가해야 함 .project( target: "BarFeatureInterface", path: .relativeToRoot("Projects/Feature/Bar") ), .project( target: "BazFeatureInterface", path: .relativeToRoot("Projects
swift
tuist
연관 기술 스택

Swift