티스토리 뷰
올해 초 회사 프로젝트에 큰 변화가 있었다. 단일타겟이였던 앱 프로젝트를 멀티모듈로 전환했다.
신규 기능 개발 + 유지보수 와 함께 병행해야 했기 때문에 시간 분배가 필요했고, 약 2-3개월 정도 소요되었다.
1. 왜 멀티모듈로 전환했나요?
A. 코드 관리의 측면
프로젝트가 다른 슈퍼앱처럼 엄청 방대한 사이즈는 아니지만 그렇다고 아주 작은 사이즈는 아니였다.
컨벤션이 없는 상태에서 많은 사람들의 손을 거쳐왔고, 네이티브로 구현된 많은 기능과 코드가 존재했다.
따라서 IntelliSense(코드 자동완성) 도 느렸고 빌드도 느리고 모든게 다 느려 생산성이 떨어진다 생각이 들었다.
거기에 올해 예정되어있는 많은 추가 개발 기능 건 들은 나의 마음을 답답하게 만들었다.
B. SwiftUI 도입 추진
SwiftUI가 출시된지 좀 되었고, 작년부터는 타 기업에서도 도입하며 사용성이 검증되고 있었다.
우리도 도입을 추진하여 여러가지 테스트를 해본 결과, SwiftUI의 Preview 빌드 시간이 길어 큰 장점중 하나가 없어졌다.
SwiftUI 를 본격 도입하기 전에 모듈 분리 부터 진행해야 한다고 생각했다.
C. 테스트코드
단일 타겟 프로젝트로 구성되었던 우리 프로젝트는 부끄럽지만 테스트 코드가 존재하지 않았다.
그래서 중요한 피처들은 사람이 테스트를 하였기 떄문에 생산성이 떨어졌고,
유지보수를 하는 입장에서 부담스러울 때도 있었다.
또한 신규 기능들 부터라도 테스트 코드를 작성하고자 했으나, 단일 타겟이였기 때문에 빌드 타임이 길어 어려웠다.
자료를 찾아보던 중 이 영상에서 TDD를 도입하기 전에 모듈화 먼저 진행해 빌드타임을 줄이라고 했다.
이러한 크게 세가지 이유로 모듈화는 반드시 필요하다고 생각했고,
회사의 승인을 받아 모듈화를 진행하기로 했다.
2. 어느 단위로 모듈화를 해야할까요?
그렇게 모듈화를 진행중에 많은 문제들을 만났고 고민들을 했었는데
가장 많은 고민을 했었고, 현재도 고민중인 부분이다.
각 모듈의 단위를 어디까지 지정하고,
의존 관계를 어떻게 설정해야 효율적인 모듈 관계가 될 것인가? 추후 유지보수에 유연할 것인가? 고민했던 지점이다.
멀티 모듈을 도입한 타 회사의 개발 문서를 찾아보고 github의 타 프로젝트 소스코드를 참고해보니
크게 순환참조가 일어나지 않도록 단방향 의존성 구성하는 것이 중요했고, 각 layer 를 나눠 관리하고 있었다.
그렇게 모듈 의존성을 설계했고 다음 다이어그램을 그렸다.
하위부터 살펴보면 다음과 같다
- Core 프로젝트
- Auth: 로그인 데이터들 및 유저 관리 등을 담당하는 모듈
- CoreKit: Swift의 Foundation 프레임워크처럼 현 프로젝트의 기초 뼈대를 담당하는 모듈 (Extension, Menu 등 전역적으로 사용되는 코드들)
- Service: 네트워크 통신 관련 모듈
- PaymentCore: 결제 관련 코어 모듈
- DesignSystem 디자인 컴포넌트 모듈
- 디자인 시스템에 들어가는 컬러, 이미지, 기본 컴포넌트들은 이곳에 적용
- CommonUI 프로젝트 공통화 되어 사용되는 UI 컴포넌트들
- 디자인 시스템과의 차이점
- CommonUI 는 특정 UI 의 뼈대를 담당하는 부모 ViewController. 즉, 부모 혹은 인터페이스로써 로직이 들어간 것
- 디자인 시스템은 컴포넌트이며, CommonUI는 로직이 들어가 기능을 수행하는 것을 포함하는 컴포넌트로 구분
- 결제: PaymentCore를 의존하는 PaymentKit(뷰를 포함)
- 주소검색 뷰, 전화 인증, 사진선택 등 앱에서 계속 재사용 되는 세그먼트 뷰 등
- 단독으로는 기능을 완성하지 못하므로, 필요한 Feature에서 import 해서 사용하도록 설계
- Feature 프로젝트 앱 내 각 기능들
- 앱 내에서 유저들이 직접 사용하는 기능 하나하나를 Feature 프로젝트 내 하위 27개의 모듈로 쪼갬
- 신규 기능 추가시 필요한 기능들을 조립하여 Feature 모듈을 만들어 개발하는 방향
- App
- 개발된 모든 Feature들을 조립해 하나의 모듈을 만듬
- 이외에 WatchApp, Extension 등 포함
이렇게 약 55개의 멀티모듈 구조로 마이그레이션을 진행했고,
현재 구조의 멀티모듈이 정답이고 잘 설계되었는지는 모른다.
다만, 여러 프로젝트들을 살펴보니 각 프로젝트별로 구조가 조금씩은 다르고 구성에 정답은 없었다.
단방향 의존관계를 지키기 위해 많은 코드들 변경이 필요해 머리가 아팠지만,
덕분에 현재 프로젝트에서 모듈간의 순환참조는 없다.
모듈 관계에 대한 고민은 계속 진행중이며 조금씩 구조를 바꿔가며 고민해봐야 할 부분이다!
3. 프로젝트 관리하기 (Tuist)
멀티모듈과 Tuist는 관련이 없다. Tuist 는 Xcode 프로젝트를 관리하는 도구다.
모듈화는 Xcode 자체로 진행할수도 있고, SPM 등을 이용하는 방법도 있다.
다만, 현 시점에서 멀티모듈로 구성된 프로젝트를 관리하기에 좋은 도구라고 생각이 들었고,
코코아팟으로 관리되던 기존 프로젝트 협업중에 XcodeProj Conflict를 자주 만났었기 떄문에
이번 프로젝트를 뒤집는(?) 기회에 Tuist까지 적용하기로 했다.
4. SPM을 지원 안하는 라이브러리가 있다고?
Tuist 는 SPM은 지원하지만 Cocoapod은 공식적으로 지원하지 않는다.
최신 업데이트가 이루어지는 라이브러리들은 SPM 을 대부분 지원하지만,
우리 프로젝트에는 그렇지 레거시 라이브러리들도 다수 존재했다.
우선, 최대한 해당되는 라이브러리들을 제거하는 작업을 했다.
작업 가능한 범위에서 업데이트 되지 않는 옛날 라이브러리들은 과감하게 빼버렸고,
직접 구현하거나 타 라이브러리로 교체하는 작업을 진행했다.
(묵은때를 벗겨내는 느낌)
하지만 작업량이 크거나 제거하기 어려운 라이브러리들이 몇몇 있었다.
이 경우에는 고민을 많이 했는데 방법이 없었다.
방법이라면 직접 라이브러리를 받아서 하나의 모듈로 만들었다.
하나의 모듈로 직접 만든 라이브러리를 필요한 곳에 import 하여 사용하는 방식으로 해결했다.
--
이러저러한 이슈들을 많이 만났다.
특히 프로젝트는 3rd party Static 라이브러리도 포함되어있었고,
프로젝트 빌드 세팅에서 발생했던 이슈도 있었는데, 따로 포스팅을 해보려고 한다.
(그리고 굉장히 노가다였다..)
이렇게 약 2-3개월동안 프로젝트를 틈틈히 멀티모듈로 재구성했고,
2024년 3월에 멀티모듈로 마이그레이션 한 버전이 업데이트 되었다.
처음 문제가 되었던 세가지는 다음처럼 해결이 되었다고 생각한다.
A. 코드관리
- 모듈별로 코드를 관리함
- 각 개발자는 맡은 모듈을 개발하고 수정함
- 증분빌드 속도 70% 이상 증가로 생산성 급증!
B. SwiftUI
- 멀티모듈 전환 시점부터 즉시 사용을 도입함
- 편차는 있지만 UI 개발이 2배가량 빨라짐
C. 테스트코드
- 하위 모듈부터 테스트 코드 조금씩 도입중
- Fastlane 으로 테스트 이후 업로드 되도록 설정
가장 좋은 점은 하나의 모듈 빌드시간이 획기적으로 단축되었다.
그 결과 SwiftUI 도 도입했고, 테스트코드도 일부지만 도입하여 프로젝트 관리를 더욱 안정적으로 할 수 있게 되었다.
또 확실히 Tuist를 도입하니 컨플릭트에서 자유로워져서 개발중 걱정이 덜해졌다.
이런 저런 버그 리포트들이 들어왔지만, 모두 개선해 2024년 5월 현재는 안정적으로 올라갔다고 판단한다.
2024년 상반기는 멀티모듈, Tuist와 함께해서 하하 즐거웠다!
'iOS' 카테고리의 다른 글
[iOS] Github Action 과 Tuist test 로 테스트 자동화 구축 (0) | 2024.08.20 |
---|---|
[iOS] Dateformatter 가 고장나서 이상했던 경험 (0) | 2024.08.07 |
[iOS] SwiftUI에서 커스텀 Alert 만들기(Animation도) (0) | 2024.05.01 |
[iOS] SwiftUI 섹션이 있는 메뉴 리스트 만들기 (0) | 2024.04.22 |
[iOS] 서버 환경 분리하기(prod/dev, with Tuist) (0) | 2024.04.19 |
- Total
- Today
- Yesterday
- Xcode15
- locale
- swift날짜
- watchOS
- flo
- 소수점
- easy cue
- IOS
- TextField
- retry
- Xcode
- 애플워치 데이터 전송
- watch connectivity
- DateFormatter
- OAS
- 애플워치
- demical
- auth
- 회고
- SwiftUI
- AVFoundation
- open-api-generator
- 토큰
- openapi-generator
- musicplayer
- keyboardtype
- Swift
- 2024년
- KVO
- avplayer
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |