Modular Architecture on iOS App, Part 1

what's up dooray!

Posted by Kim Heebeom on August 24, 2019

Modular Architecture

Preface

입사 후 가장 좋은 점은 큰 규모의 앱을 많이 접해볼 수 있다는 것이다. 그중에서도 Dooray! 서비스는 가장 애착이 가고 많이 참여했던 프로젝트이기도 하다. 두레이 서비스에 애착이 가는 건 훌륭한 서비스라서 인 것도 있지만, 최대 관심사인 아키텍처, 클린 코드에 대한 고민을 많이 하게 해준 서비스였고 입사 후 첫 프로젝트이기 때문일 것이다.

운이 좋게도(?) 두레이 앱이 가진 문제가 최근 관심사였던 Modular Architecture를 적용해보기에 아주 좋은 교재라 생각되어서 모듈화를 진행하게 되었고, 그 내용에 대해서 공유하고자 한다.

Dooray!

우리 회사에서 개발하고 있는 워크플레이스다. 프로젝트, 메일, 캘린더, 위키, 드라이브, 메신저가 주서비스이고 내가 했던 두레이 앱은 프로젝트, 메일, 캘린더가 합쳐진 것이다, 두레이 메신저는 메신저 서비스만 들어가 있다. 아직 위키와 드라이브는 구현이 안 된 상태였지만 니즈가 있어서 두레이 앱에 포함해야 하는 상황이었다.

위키와 드라이브 서비스를 넣는다고 했을 때 가장 먼저 든 생각이 바로 모듈화였다. 커질 대로 커진 앱을 따로따로 나누는 의견도 있었기 때문에 기존에 구현된 형태에 그대로 위키와 드라이브를 추가하는 것이 맞는가 하는 생각이 들었다.

빌드 시간도 빼놓을 수 없다. 클린 빌드를 하면 6~7분 정도가 소요됐는데, 그 정도도 나에겐 너무 긴 시간처럼 느껴졌다. 모듈화를 통해 충분히 개선할 수 있는 부분이었다. 전체 소스를 컴파일하는 게 아니라 변경사항이 있는 모듈만 컴파일하면 되기 때문에 기능 단위로 쪼개면 그만큼 빌드 효율이 올라갈 것이다.


Modular with layered architecture

모듈화를 진행하기 전 앱의 구성이다.

UI 레이어와 비즈니스 로직이 담긴 Service 레이어가 명확하게(사실 내부를 들여다보면 완전 명확하진 않게,) 구분되어 있다. 여기서 나의 목표는 레이어별 수직적 분할 뿐만 아니라 성격이 전혀 다른 서비스(프로젝트, 메일, 캘린더)들을 수평적으로 완전히 떼어내는 것이다.

처음 구상했던 형태이다. 서비스 모듈들을 완전히 분할하였고, 각 서비스 모듈들을 포함하는 앱이 있다.

그다음엔 추가될 기능들과 공통으로 사용될 모듈까지 분할하였다.

기존의 두레이 앱이 프로젝트, 메일, 캘린더가 유기적으로 뭉친 하나의 형태로 보였다면, 현재의 두레이 앱은 껍데기만 존재하고, 서비스 모듈들의 조합으로 이루어진 형태를 보인다.

Main

Dooray, Dooray Messenger처럼 AppDelegate를 포함하는 앱이라고 보면 된다. 기능에 대한 구현이 거의 들어가지 않는다. 다만 컨테이너 같은 역할을 한다. 각 모듈에 configuration을 주입하고, TabBar같은 root view를 포함한다. 모듈 간에 뷰 전환을 제어한다.

Service Frameworks

다른 표현으로 Feature Frameworks라는 용어가 있긴 하지만 개인적으로 Service라는 용어를 선호한다. 각 기능에 대한 모듈들이다. 상호 독립적이며, 내부 뷰 전환을 Main App에서조차 알 수 없다. 단지 coordinator를 Main App에 위임한다.

Common Frameworks

여기서 말하는 Common은 여러 모듈에서 공통으로 사용되는 모듈들을 통칭하는 이름이다. (물론 실제 모듈 이름이 Common일 수도 있다) Common 영역을 감싸고 있는 박스 또한 물리적인 구분이 아니라 외부에서 Common에 있는 것을 공유한다는 논리적인 구분이다. 모든 모듈에서 Core를 사용할 수도 있고, 아닐 수도 있다. (모듈화의 목적이 드러나는 부분이다. 나는 지금 서로 다른 두 앱에서 AccountCore를 공유하기 위해 이 작업을 하고 있다.!)


In practice

이제 위 구성을 바탕으로 앱을 새로 만들 차례이다.

기존 두레이가 가지고 있던 구조이다. 보통의 프로젝트가 이런 형태가 아닐까 싶다. 하나의 워크스페이스에 하나의 프로젝트를 갖고 있다. 하지만 앱이 커진다면 더는 환영받을 수 없는 구조이다. 새로 구성해보자.

새로 프로젝트를 생성하고 File → Save as Workspace… 로 워크스페이스를 생성한다. (Cocoapods을 사용해봤다면 처음 install에 워크스페이스를 자동으로 생성해주지만, 당장 팟을 추가할 건 아니니 일단 수동으로 만들었다)

이제 각 서비스가 될 모듈들을 추가해줄 차례이다.

  1. File → New → Project…
  2. 템플릿에서 Cocoa Touch Framework 을 선택
  3. 모듈명을 정하고 Next
  4. 디렉토리를 선택하는 화면이 나올 것이다. 워크스페이스와 동일한 디렉토리를 선택한다(아마 기본이 그럴 것이다)
  5. Add to 에서 워크스페이스를 선택한다. 마찬가지로 Group 에서도 워크스페이스를 선택한다.

프로젝트를 모두 추가하고 나면 이런 구조가 된다. Dooray 프로젝트는 AppDelegate가 있는 메인 프로젝트이고, 나머지는 기능들을 담은 프레임워크이다.

이제는 각 모듈에 링크를 걸어줄 차례이다. 메인 프로젝트의 타겟으로 이동해서 Embedded Binaries에 추가한다.

그러고 나면, 아래처럼 Linked Frameworks and Libraries 에도 추가가 된다.

이제 메인 프로젝트에서 각 모듈을 사용할 준비가 되었다.


서비스들을 모듈로 분리하는 것 말고도 아주 중요한 부분이 남아있다. :( 모듈 간에 의존성을 모두 제거한 후엔 메인에서 의존성과 설정을 주입해주는 작업이 필요한데 그러어어어케 복잡하진 않고… 조금 복잡하다. 그건 다음 포스팅에서! 👉 modular-architecture-ios-part-2