RxFlow 파트 1 : 이론
2018.11.14
#RxSwift • #RxFlow • #Architecture
by Thibault Wittemberg, translated by pilgwon
당분간 이 블로그의 가장 주목받을 시리즈의 첫 글입니다. 저는 RxFlow 를 소개하고자 합니다. RxFlow 는 iOS 어플리케이션에서 Reactive Flow Coordinator를 구현해주는 프레임워크입니다. RxFlow 프로젝트는 RxSwiftCommunity의 도움을 받고 있습니다.
사실
iOS 어플리케이션에서 네비게이션에 관해서는 두 가지 선택지가 존재합니다.
- Apple과 Xcode에서 제공하는 내장된 매커니즘인 storyboard와 segues를 사용합니다
- 코드에서 직접 커스텀 매커니즘을 구현합니다
위 두 방법엔 단점이 있습니다.
- 내장된 매커니즘: 네비게이션은 상대적으로 정적이고 스토리보드는 거대해서 네비게이션 코드는 UIViewController를 오염시킵니다.
- 커스텀 매커니즘: 코드 자체가 어려울 수도 있고 어떤 디자인 패턴(Router, Coordinator)을 선택하는지에 따라 복잡해질 수도 있습니다.
다음은 RxFlow 가 목표로 하는 사항입니다.
- 스토리보드를 유닛 단위로 쪼개서 UIViewController의 재사용성을 키웁니다
- 네비게이션의 흐름(context)에 맞게 UIViewController를 다른 방식으로 보여줄 수 있습니다
- 의존성 주입(Dependency Injection)을 쉽게 구현할 수 있습니다
- UIViewController에 있는 모든 네비게이션 매커니즘을 삭제합니다
- 반응형 프로그래밍(Reactive Programming) 사용을 촉진합니다
- 네비게이션에서 일어나는 대부분의 케이스를 처리하면서 선언형으로 표현할 수 있습니다
- 어플리케이션을 네비게이션의 논리적인 블록으로 나눌 수 있습니다
Storyboard 에서 Coordinator 패턴까지
iOS 개발 경험이 쌓일수록 저는 지속해서 네비게이션에 대한 의문을 가져왔습니다. 다른 개념적인 이슈의 경우엔 수많은 패턴이 존재합니다(MVC, MVP, MVVM, VIPER, …).
하지만 네비게이션을 설계할 때마다 저는 끝나지 않는 질문에 갈가리 찢겨 버렸습니다.
- Storyboard/Segues를 사용할 때 의존성 주입은 어떻게 해야 하지?
- 어플리케이션의 흐름은 어떻게 제어해야 할까?
- UIViewController에서 쓰이는 네비게이션에 대한 보일러 플레이트 코드를 없앨 순 없을까?
시간이 지나면서 전의 iOS 어플리케이션에 대한 구상은 하나의 스토리보드가 있는 MVC에서 여러 스토리보드가 있는 MVC까지 뻗어 나갔고, 결국엔 MVVM과 Flow Coordinator 에 닿았습니다. Flow Coordinator 가 완벽한 예시인 이유는 의존성 주입을 가지고 놀 수 있으며 UIViewController를 재사용이 가능하며 테스트도 쉽게 만들기 때문입니다. 저는 이 패턴을 크고 복잡하며 실제로 서비스 중인 어플리케이션에 적용할 기회가 있었습니다. 하지만 결국엔 다음과 같은 이슈들이 저를 꾸준히 괴롭혔습니다.
- 매번 Coordinator 패턴을 작성해야 했습니다.
- ViewModel이 Coordinator와 커뮤니케이션하기 위한 Delegation 패턴이 아주 많았습니다.
- 특히 네비게이션 상태 매커니즘을 위해 Redux 패턴에 대해 알아보기 시작했습니다. RxSwift와 Observable로 노출하는 전역 네비게이션 상태가 있었고 이 상태의 변화를 듣고 네비게이션을 움직일 수 있었습니다. 제가 찾은 장애물은 이 네비게이션 상태의 희소성과 그것이 가질 수 있는 책임을 아무도 제어하고 있지 않다는 것이었습니다.
네비게이션은 단계적으로 수정될 수 있는 상태를 반영하기만 한다는 아이디어가 떠오르기 시작했습니다. 상태가 모든 어플리케이션 구조에 퍼지고, 한 공간에 저장되지 않고 관찰자에 의해 통합되어 결과적으로 네비게이션을 조종하는 것입니다. 지금부터는 어플리케이션에 흩어지는 작은 상태들을 Step 이라고 부르고 관찰자를 Coordinator 라고 부르겠습니다.
RxFlow 는 이러한 경험들과 전통적인 Coordinator 패턴에 남아있는 다음과 같은 두 가지 걱정에서 태어났습니다.
- 개발자는 이제는 Coordinator를 작성하지 말아야 하며, 그들은 오직 네비게이션과 반응할 상태를 정의해야 한다
- 상태는 Loom에 의해 관찰되는 RxSwift Observable이기 때문에 Delegation은 더 이상 필요하지 않다
주요 원칙
Coordinator 패턴에 대해 더 알고 싶다면 Coordinator Redux라는 글을 추천해 드립니다.
Coordinator 패턴은 매우 좋은 아키텍쳐이지만 몇 가지 문제점이 존재합니다.
- 어플리케이션을 만들 때마다 Coordinator 매커니즘을 작성해야 합니다
- Coordinator와 커뮤니케이션하기 위한 Delegation 패턴 때문에 아주 많은 양의 보일러 플레이트 코드가 존재합니다
RxFlow는 Coordinator 패턴을 반응형으로 구현한 것입니다. 아키텍쳐의 좋은 점은 모두 가져왔습니다. 무엇이 바뀌었는지 알려드리겠습니다.
- 네비게이션을 더 선언형으로 만들어줍니다
- 우리가 선언한 네비게이션 흐름을 조절하기 위한 내장 Coordinator를 제공합니다
- 반응형 프로그래밍을 사용해서 Coordinator와 커뮤니케이션 이슈를 해결했습니다
다음은 RxFlow를 이해하기 위해 친해져야 할 용어들입니다.
- Flow: Flow는 어플리케이션의 네비게이션 공간을 규정합니다. 이 공간에서는 우리가 네비게이션 액션들을 선언할 수 있습니다. (UIViewController 또는 다른 Flow를 띄우는 것처럼요)
- Step: Step은 어플리케이션의 네비게이션 상태입니다. Flow와 Step을 조합하면 가능한 모든 네비게이션 액션을 설명할 수 있습니다. Step은 내부 값(Ids, URLs 등이 있습니다)을 임베드할 수 있어서 Flow에 선언된 화면에 전달할 수도 있습니다.
- Stepper: Step을 발생시킨다면 무엇이든 될 수 있습니다. Stepper는 Flow의 모든 네비게이션 액션을 트리거해야 합니다.
- Presentable: 보일(present) 수 있는 무언가를 추상화한 것입니다. (기본적으로 UIViewController와 Flow가 Presentable입니다) Presentable은 Reactive 옵저버블을 제공하고 Coordinator가 Flow와 Step을 UIKit에서 더 편한 방식으로 조종하기 위해 이를 구독합니다.
- Flowable: Presentable과 Stepper를 조합하는 간단한 데이터 구조입니다. Flowable은 우리의 Reactive 매커니즘의 새로운 Step이 생성할 게 무엇인지 Coordinator에게 알려줍니다.
- Coordinator: 네비게이션 가능성을 표현하는 Flow와 Step의 적절한 조합을 정의했다면 Coordinator가 해야 할 일은 이 조합을 지속해서 잘 섞는 것입니다.
첫 글은 이 프레임워크의 개념적이고 이론적인 측면만 알아보는 시간이었습니다. 다음에는 RxFlow 의 기술적인 측면에 관해 얘기해보겠습니다.
RxFlow 의 GitHub 저장소와 데모 어플리케이션은 다음 주소에서 확인하실 수 있습니다. https://github.com/RxSwiftCommunity/RxFlow
채널 고정!