Modular Architecture on iOS App, Part 2

dependency & configuration

Posted by Kim Heebeom on August 31, 2019

이번엔 지난 포스트에서 만들었던 프로젝트를 토대로 Dependency & Configuration이라는 주제로 다뤄볼 것이다.


Different ways to share code between apps

모듈(프레임워크)을 프로젝트의 타겟에 포함해서 나눌 수도 있지만, 각각의 프로젝트로 생성해야 했던 이유는 동일한 코드베이스의 두 앱이 있기 때문이다. 그 외에도 앱 간에 코드를 공유하는 방법은 여러 가지가 존재한다.

  1. Single project with multiple targets: 거의 동일한 기능의 두 앱에 서로 다른 브랜딩만 존재한다면 우리가 가진 선택지 중에 가장 간단하고 매력적인 방법일 것이다. 모듈을 타겟으로 분리하면 코드 공유라는 목적을 이루는 동시에 관리하기 수월하다는 장점도 있다. 하지만 하나의 Xcode project가 비약적으로 커질 수 있기 때문에 무조건으로 추천하는 방법은 아니다.
  2. Internal pods: 모듈을 오픈소스로 만들지 않고 코드를 공유할 수 있는 아주 유용한 방법이다. 예를 들어 인증을 위한 화면과, 로직, 기타 컴포넌트들을 pod으로 만들어 cocoapods의 trunk에 등록하지 않고 내부적으로 공유하는 방식이다. 그렇다고 공유되지 않는 코드들 조차 내부 pod으로 만들어 사용하는 방식은 모듈 간의 버전 관리, pod update를 계속 해야 하는 등의 리소스가 많이 들기 때문에 적절치 않다.
  3. Multiple Xcode projects: 물리적으로, 논리적으로 코드의 분리라는 개념이 명확하게 적용된 케이스이다. 3th party 의존성이 각 모듈이 아니라 모듈을 포함하는 앱에 의해 관리된다는 단점이 존재하지만 확장성 측면에서 가장 열려있는 방식이다. 그리고 부분적으로 internal pods을 만드는 방식을 결합하면 의존성 문제도 극복할 수 있다.

Setting up Pods for multiple modules

Cocoapods을 사용한다면 각 타겟마다 필요한 라이브러리를 추가해줘야하고, 메인 타겟에는 각 모듈에서 사용된 모든 라이브러리를 추가해야만 한다.

Tips: 비슷한 성격의 의존성끼리 함수로 묶어 사용하면 각 타겟에서 버전관리가 수월해진다.

# config
platform :ios, '11.0'
workspace 'Workplace'

use_frameworks!
inhibit_all_warnings!

def common
  pod 'SwiftLint'
  pod 'Swinject'
end

def networking
  pod 'Alamofire'
  pod 'Moya'
  pod 'Moya/RxSwift'
end

def rx
  pod 'RxSwift'
  pod 'RxCocoa'
end

def ui
  pod 'SnapKit'
  pod 'Hero'
end

#
# targets
#
target 'Workplace' do
  common
  networking
  rx
  ui
end

target 'Core' do
  project 'Core/Core'
  common
  networking
  rx
end

target 'Account' do
  project 'Account/Account'
  common
  rx
  ui
end

target 'AccountService' do
  project 'Account/Account'
  common
  networking
  rx
end

How to configure Modules