-
새로운 앱을 만들기 위한 기술스택 선정하기iOS 2022. 6. 30. 11:44
안녕하세요. 그린입니다🟢
이번 주제에서는 새로운 앱을 만들때 꼭 필요한 기술 스택에 대해 얘기를 나눠보려고해요.
지극히 제 주관적인 부분이기에 공감이 안될 수도 있으니 참고해주시면 좋겠습니다🙇🏻
기술스택 선정이 중요한 이유
현업에서 혹은 개인/팀 프로젝트에서 새로운 프로덕트를 처음부터 끝까지 만들어보는것은 개발자의 성장에도 영향이 있겠지만 만들어지는 프로덕트에도 꽤나 큰 영향을 끼칠거라고 생각해요.
지금 선택한 기술스택으로 만들어진 프로덕트가 향후 리팩토링 수준을 넘어 재개발하는 정도가 아니라면 현실적으로 다시 판을 갈아엎고 전체 기술스택을 다시 정하고 재개발을 하기란 생각보다 아주 많이 힘드니까요!
그렇기에 프로덕트 즉, 새로운 앱을 잘 만들기 위해서는 첫 단추를 잘 꿰야할것이고 그 시작이 기술스택을 선정하는 과정이라고 생각합니다.
기술스택을 선정해야할 부분
제가 생각했을때 넓은 범주에서는 총 6개 파트로 기술스택을 선정할 수 있을것 같아요.
첫째, 뷰를 그리는 View Drawing 파트
둘째, 전체 앱의 구조를 담당해줄 Architecture
셋째, 비동기 처리의 기술은 Asynchronous
넷째, 네트워크 통신을 처리할 Network
다섯째, 이미지 로드 및 캐싱을 수행할 Image Loader
마지막, 그 외 프로덕트 개발에 도움을 줄 수 있는 기타 Library들
기술스택을 선정하기 위한 체크 포인트
1. 외부 라이브러리 사용에 대한 범주
우선 앱을 개발하면서 순수하게 외부 라이브러리 사용없이 갈 수도 있습니다.
반면 많은 부분을 외부 라이브러리에 의존하며 편리한 구현을 해줄 수도 있죠.
각각 일장일단이 있기에 이건 정말 속한 개발팀의 성향 및 방향성에 결정되겠지만 저는 최대한 외부 라이브러리 의존성을 지양하는쪽을 선정하려합니다.
다들 아시다시피 외부 라이브러리에 의존하게되면 추후 지원 종료가 되거나 다른 라이브러리로 갈아탈때 많은 리소스가 들고 또한 업데이트가 될 시에 주기적인 팔로업이 없다면 예기치 못한 이슈가 생길 확률이 다분합니다.
결국 언젠가 전체 리팩토링을 해야할 타이밍이 올 수 있다고 생각합니다.
다만 지양하자이지 근절하자가 아니기에 여러 기준을 같이 만족시키는 동등한 선택지가 있다면 외부 라이브러리 선택을 후순위로 두자입니다!
2. 향후를 생각한 미니멈 타겟을 고려하여 기술스택 선정
즉 현재 만들어질 앱이 1~2년 후 재개발을 거치면서 기술스택을 선정이 다시 이뤄지는것이 아니라는 가정하에 오래 유지보수될 수 있도록 우선적으로 미니멈 타겟을 향후를 생각하면 좋을것 같아요.
물론 회사마다 서비스되는것이 다르고 이에 미니멈 타겟을 올리고 싶어도 못올리는 경우도 분명 존재합니다.
이런 경우를 제외하고 지금 새로운 서비스를 만든다고 생각하고 저의 기준을 삼았습니다.
보시는것과 같이 현재 82%의 기기가 iOS 15 이상을 사용하고 있고 14 이상까지 합치면 96%로 iOS 13을 더이상 회사 서비스 측면이 아니라면 가져갈 이유가 크게 없다고 생각합니다.
더군다나 저 비율은 2022년 5월 31일에 집계된 앱 스토어의 자료로 iOS 16이 아직 출시되지도 않은 상황임을 감안하면 올 가을 이후는 iOS 15 비율이 훨씬 더 늘어날것 같아요.
그렇기에 현재 새로운 서비스를 만든다면 저는 iOS 15를 미니멈 타겟으로 잡으면 좋을것 같습니다.
3. 현업 및 팀에서 여러 서비스를 함께 제공한다면 최대한 통일된 기술스택을 사용
한 조직에서 여러 서비스를 제공하는 경우 분명 빨리 만들어진것 그 후에 만들어진 서비스가 존재할겁니다.
이에 완전 다르지는 않지만 기술스택이 조금씩 차이나는 부분이 분명 존재할 수 있을거에요.
그렇기에 작업자들이 각 도메인에 대해 크로스로 업무를 쳐내는것에 다시 익숙해지는 시간 비용이 들어가게 됩니다.
그렇기에 만약 새로 다 서비스를 초기 구축하는것이라고 생각하면 추후 만들어질 서비스들도 예측하고 다 같이 사용될 수 있는 기술 스택 선정이 포인트가 될것 같아요.
즉, 개발자들이 각 서비스의 도메인 지식을 쌓기 위한 시간 리소스 외에 기술적인 러닝커브 리소스를 줄이면 좋을것 같습니다.
View Drawing
iOS에서는 뷰를 그리기 위한 다양한 기술이 존재합니다.
제가 생각할때 현재 화두가 되었고 대표적이라 할만한 4개의 기술을 리스트업 해보려합니다.
1. UIKit
이제 애플의 철학은 어느정도 공식적으로 "누구나 개발을 할 수 있게하자"라는 모토입니다.
즉 개발자가 아니더라도 누구나 쉽게 코딩을 할 수 있도록 하기 위함이죠.
그렇기에 오토레이아웃을 잡는다던지 점점 복잡할수록 이해하기 힘든 UIKit 대신 선언형의 SwiftUI를 어느정도 반 공식적인 애플의 뷰 드로잉 기술로 요즘 밀어가고 있다고 보입니다.
얼마전 WWDC2022에서도 SwiftUI 4.0으로 업데이트가 소개되면서 더욱 SwiftUI에 힘을 실어주고 UIKit은 점차 지는해의 느낌을 받았습니다.
2. SwiftUI
위 설명 외에 덧붙이자면 기존 SwiftUI의 잔버그들을 어떻게든 우회하여 SwiftUI에서 제공하는 기본 API들을 직접 커스텀하게 제작해 사용해도 됩니다.
물론 파생되어 어떤 이슈가 있을 수도 있겠지만 결국 UIKit을 포팅한거기에 커스텀하게는 가능할거라 생각해요.
시간 리소스만 걱정 없다면 그 방법도 좋은 방법이라고 생각합니다.
3. Texture
위의 설명과 같이 너무 좋은 라이브러리라 생각은 됩니다.
다만 외부 라이브러리이고 사실상 관리가 잘 이뤄지고 있지 않다고 생각합니다.
그거 외엔 괜찮을것 같은데... 새로 만드는것에 모험을 하기 꺼려지네요.
4. FlexLayout & PinLayout
텍스쳐와 마찬가지로 외부 라이브러리이고 개인적으로 SwiftUI 처럼 쉽고 간결하고 직관적이여서 좋은 사용 경험이 있습니다.
PinLayout이 CSS 절대 위치 지정 방식을 차용해 만든 프레임워크이다보니 더 세밀한 뷰 제어 및 애니메이션을 구현할때 탁월합니다.
또한 보시는것처럼 백 그라운드에서 그려주기에 메인 스레드에서 뷰를 그려주는 UIKit보다 수치 상 8~12배 정도 성능이 좋습니다.
여기까지 제가 생각했을때 뷰 드로잉을 하기 위한 기술들을 리스트업을 해봤습니다.
저는 개인적으로 SwiftUI 혹은 FlexLayout&PinLayout 둘중 선택할것 같아요.
이유는 지는해인 UIKit을 제외, 관리가 안되는 라이브러리인 Texture를 제외합니다.
근데 여기서도 둘중 굳이 고르자면 미니멈타겟을 저는 최소 13은 포함되지 않을것이기에 SwiftUI로 가면 좋을것 같습니다.
문제되는 부분은 커스텀하게 구현하구요.
왜냐하면 FlexLayout&PinLayout도 결국 외부 라이브러리이니까요.
Architecture
아키텍쳐는 정말 무수히 다양하지만 저는 모든걸 리스트업하지 않고 제가 사용해봤을때 가장 핫하고 이상적이라 생각한
The Composable Architecture 줄여서 TCA라 칭하겠습니다.
이 TCA를 아키텍쳐로 삼으면 어떨까 합니다.
우선 TCA는 엘름 아키텍쳐, 리덕스 등에서 영감을 받아 PointFree에서 만든 상태관리 기반 단방향 아키텍쳐입니다.
TCA를 택하고 이렇게 극찬하는 이유가 있겠죠?
이 파트에서는 TCA의 장점이 무엇이며 어떤것인지 간략히 소개해볼까해요.
TCA는 5가지의 장점을 극대화 해줍니다.
첫째, State Management
상태 관리로 단순 값 유형을 통해 앱 상태를 관리하며 여러 뷰에서 상태를 공유할 수 있고 편리합니다.
둘째, Composition
각각의 도메인을 작은 모듈로 추출하고 기능 구현을 위해 다시 합치는 등 자유로운 구성이 가능합니다.
pullback과 같은 오퍼레이터를 통해 도메인간 연결이 쉽고 재사용성에 용이한 장점을 지닙니다.
셋째, SideEffect
앱의 특정 부분에서 이해하기 쉬운 방식으로 외부와 통신할 수 있는 구조로 편리합니다.
넷째, Testing
TCA의 리듀서 자체는 아주 순수하기에 매번 동일한 결과를 보장합니다.
그말인 즉슨 전체 및 부분으로 구성된 기능에 통합 및 부분적 테스트에 용이합니다.
다섯째, Code Rules
TCA는 정형화된 규칙이 있어 아예 처음 접할때는 러닝커브가 조금 있지만 익숙해지면 피쳐 구현이나 팀원간 코드 리뷰를 하거나 그 외 기술적 커뮤니케이션에 있어 많은 시간 비용을 아낄 수 있습니다.
실제로 View/Core단의 두 파일로 정형화하여 저는 사용하고 있으며 그 안에서도 PointFree의 기조를 따라 어느정도 정형화해 사용함으로 여러 코드에서 통일성을 극대화 시키고 있습니다.
TCA의 기본 구성 및 상태관리를 위한 단방향 흐름
우선 5가지의 기본 구성으로 이뤄집니다.
첫째, State
기능 수행 및 UI 렌더링을 위한 데이터 타입을 나타내는 상태입니다.
둘째, Action
유저 인터랙트 및 이벤트 소스 기능에서 발생할 수 있는 모든 작업 즉 말 그대로 액션이라고 불릴 수 있는 타입입니다.
셋째, Environment
API 호출 및 분석 등 사이드 이펙트에 해당하는 기능 수행에 필요한 의존성을 보유하는 타입입니다.
넷째, Reducer
액션을 통해 State를 업데이트 해주는 로직 함수로 모든 결과를 Effect 타입으로 반환해주도록 만들어 유기적인 실제 구현 역할을 해줍니다.
다섯째, Store
Store는 실제 기능을 구동하는 런타임으로 모든 사용자 작업을 스토어로 보내 스토어에서 리듀서를 실행하고 State 변화를 옵저빙해 뷰를 업데이트 해줍니다.
상태관리를 해주는 단방향 흐름은 위의 그림과 같습니다.
하나씩 흐름을 얘기해볼께요.
우선 예시를 들어서 사용자가 주문 버튼을 누른다고 가정해볼께요.
그러면 주문 버튼 자체는 뷰에 있을것이고 이 뷰에서 주문 버튼을 누르는 사용자 인터랙트가 먼저 발생합니다.
그러면 이 인터랙트를 액션이 받습니다.
액션들은 열거 타입으로 정의되어 있으며 발생한 액션을 리듀서에서 switch문을 통해 해당하는 액션 분기를 처리해줍니다.
그렇기에 액션은 리듀서로 연결됩니다.
그럼 리듀서는 대표적으로 3가지를 할 수 있어요.
첫째, 주문 버튼이 눌렸음에 다음 화면으로 넘어갈 수 있도록 State를 변경할 수 있습니다.
둘째, Environment를 통해 실제 주문 API를 호출할 수 있습니다.
셋째, Effect 타입으로 반환해 이어서 새로운 액션 즉 재고가 없을 시 얼럿을 노출시키는 액션으로 연결될 수 있습니다.
물론 이 모든 세가지를 위 보시는것과 같이 한번에 할수도 있습니다.
이렇게 정상적인 주문이 이뤄지면 상태가 변할것이고 이 상태는 View에 전달되어 UI 업데이트를 해주게 됩니다.
여기서 State, Reducer, Action의 영역들이 Store로 불리며 관리해줍니다.
보시는것처럼 아주 단방향으로 쉽게 이해가 될 수 있고 사용하기에도 좋은 아키텍쳐입니다.
Asynchronous
비동기 처리를 도와주는 여러가지 기술들이 있습니다.
아래 저는 크게 4가지로 리스트업 해봤어요.
첫째, Grand Central Dispatch(GCD) / CompletionHandler
iOS 개발을 한다면 당연히 아는 부분일거에요. 가장 기초적이죠.
가장 큰 단점은 아래와 같은 구조입니다.
이런 구조를 "파멸의 피라미드"라고 불립니다.
즉 조금만 복잡해져도 에러처리가 힘들고 무한 콜백 지옥에 빠질 수 있기 딱 좋은 구조죠.
둘째, Async/Await
아래와 같은 펑션 콜 로직을 가집니다.
아직은 SwiftUI 초창기처럼 시기 상조가 아닐까 싶긴합니다.
셋째, RxSwift
가장 현재 인기있는 유명한 비동기 처리 기술이죠.
부정할 수 없습니다.
넷째, Combine
마찬가지로 비동기 처리에서는 RxSwift와 쌍벽을 이루고 이루고 있습니다.
애플이 거의 RxSwift를 보고 그대로 만들었나 싶을 정도로 유사하더라구요.
당연 빌트인 프레임워크로 RxSwift보다 성능이 뛰어납니다.
아래와 같이 레퍼가 있습니다.
보시는것처럼 시간과 메모리 측면 모두에서 압도적이네요.
그럼 두개중에 고민한다면 Combine을 안쓸 이유가 없겠죠?
그럼 저는 개인적으로 위 비동기 처리 기술중에 RxSwift와 Combine을 고려할텐데 당연히 미니멈 타겟이 문제가 되지 않는다고 가정했으니 외부라이브러리도 아니고 성능도 더 뛰어난 Combine을 택할것 같습니다.
Network
우선 iOS에서 서버 통신을 애플에서 제공해주는 URLSession만으로도 처리할 수 있습니다.
그러나 다들 아시다시피 너무 틀이 없고 복잡하기에 이제는 애플의 퍼스트 라이브러리라고 해도 될 정도로 어느정도 자리잡고 사용되는 기술들을 보겠습니다.
첫째, Alamofire
이어서 나올것을 미리 말씀드리면 Moya인데요.
모야는 알라모파이어를 한번 더 추상화한것으로 많이들 사용하죠.
그러나 마지막에 소개했듯 커스텀하게 네트워크 레이어를 도메인에 맞게 구현한다면 굳이라는 생각이 듭니다.
둘째, Moya
그다음 모야가 있죠.
URLSession을 추상화한 Alamofire를 한번 더 추상화한 라이브러리입니다.
모야를 사용해도 충분히 괜찮지만 네트워크 레이어를 추상화한것뿐 그이상 그이하도 아니라고 보여 원한다면 제외되어도 무방해보입니다.
굳이 무겁게 들고갈 이유는 없을 수 있습니다.
저는 그렇기에 택한다면 Alamofire로 서버 통신을 해주며 네트워크 레이어를 도메인에 맞게 커스텀하게 추상화해 사용하는쪽이 더 좋을거라 생각합니다.
Image Loader
여기에 언급은 하지 않겠지만 작년 Async/Await가 애플에서 소개되면서 AsyncImage라는 애플의 이미지 캐싱 기술이 나왔습니다.
그런데 실제로 비교해보니 지금부터 소개될 기술들에 비해 아직 기능이 부족하며 성능의 이점이 없기에 배재했습니다.
이를 감안했을때 이미지 캐싱을 위한 기술로 외부 라이브러를 택하려합니다. (지양이지 근절은 아니기에🥲)
첫째, Kingfisher
가장 인식을 많이 하고 있고 유명하죠?
저의 느낌은 위 설명 외에 첨가하자면 SwiftUI보다는 UIKit에서 조금 더 친화적인 느낌이 들었습니다.
둘째, Nuke
킹피셔와 동일한 역할을 해주는 라이브러리죠.
모든 동일한 기능을 해줄 수 있고 제가 생각할땐 더욱 많이 매우 편리합니다.
특히 NukeUI가 존재하는데 SwiftUI 환경에 가장 최적화 되어 있다고 생각해요.
실제로 둘다 사용을 해봤을때 Nuke가 사용면에서 더 편리했어요.
또한 누크가 소개하는 타 이미지 캐싱 기술들과의 메인 스레드 성능 비교가 있습니다.
보시다시피 메인 스레드 캐시 처리에서 누크가 월등하네요.
뭐 사실 잘 크게 느낀건 없지만 취향차이기는 하나 저는 Nuke가 하나도 뒤쳐지는게 없다 생각해 Nuke를 택할것 같습니다.
Etc Library
두가지를 소개하려합니다.
물론 처음 라이브러리를 지양하기로 했는데 왜 쓰냐?
근절은 아니니까요ㅎㅎ..
정말 유용하고 좋은 라이브러리가 있다면 도입하는게 맞다고 생각하고 프로덕트를 만들어가는 과정에서도 추가로 도입될 수 있다고 생각합니다.
첫째, SwiftLint
너무 유명하죠.
SwiftFormat도 있지만 저는 SwiftLint가 많은 옵트인 룰을 가지고 있다고 생각하고 커스텀하기에 최적이라고 생각이 듭니다.
위 장점들로 제가 필요한 컨벤션을 아래와 같이 실제로 사용하고 있어요.
이렇게 세부적이게 린트룰을 주석과 같이 일목요연히 정리한다면 추후 팀원이 추가되거나 온보딩 시에도 어느정도 현재 팀이 어떤 코드 컨벤션을 가지고 있구나 파악하는데 시간 리소스를 줄일 수 있을겁니다.
둘째, R.swift & SwiftGen
둘다 동일한 역할을 해줘요.
어떤걸 선택할지는 자유겠지만요.
근데 저는 SwiftGen만으로 충분할것 같습니다.
R.swift를 통해 에셋 리소스를 generate 해주는 과정들을 SwiftGen에서 stencil이라는 스위프트를 위한 템플릿 언어를 사용해 템플릿화 시켜 구동시켜주면 R.swift를 걷어내도 무방합니다.
그게 충분히 되더라구요!
추가로, Tuist의 도입은 요즘은 선택아닌 필수처럼 느껴집니다.
프로젝트 관리를 효율적으로 해주고 빌드 속도를 개선시켜주고 팀원간 작업 충돌을 막아주는등 장점이 너무 많죠!
그 외 Tuist를 통해 SwiftGen의 에셋 리소스 제네레이트를 해줄 수 있는것으로 확인되어 현재 yml 파일을 마이그레이션 가능한지 파악하고 있는데 (현재 작성일 기준으로..!) 이게 충분히 커스텀화 가능하면 SwiftGen도 걷어내고 Tuist로 한번에 관리해줄 수도 있을것 같아요.
마무리
이렇게 많은 부분에서 선택할 수 있는 기술스택에 대해 제가 생각했을때 리스트업하고 제 기준에서도 선택을 해봤어요.
정말 이건 지극 지극 지극히 개인적인 선정과 리스트업입니다ㅎㅎ..
중요한건 회사 혹은 팀에서의 선정 기준을 꼭 확인해봐야합니다.
저의 선정 기준들이 도움이 되는 팀도 있길 바라며 작성해봤습니다🙌
'iOS' 카테고리의 다른 글
@main vs @UIApplicationMain (0) 2022.07.21 UIKit에서 SwiftUI로 LifeCycle 변환하기 (0) 2022.07.14 앱 출시 - 몽실(Mong:seal) (0) 2022.06.27 WWDC 2022 - 2일차 발표 요약 (0) 2022.06.09 애플 로그인 (Sign In with Apple) (2) 2022.04.18