logo
logo
모바일
RIBs
Uber에서 제작/배포한 Cross-Platfrom 모바일 아키텍쳐 프레임워크
Github Stars : ★ 7793
사용 기업
종합
푸드테크
금융/보험
소셜/컨텐츠
techstack-logo
카카오
techstack-logo
우아한형제들
techstack-logo
카카오뱅크
techstack-logo
브이씨앤씨
techstack-logo
씨제이이엔엠
techstack-logo
우아한형제들Tech
기술 블로그 글
씨제이이엔엠
왜 iOS 신규 프로젝트는 RIBs로 개발되었나
Intro안녕하세요 CJ ENM 2년차 iOS 개발자 박건희입니다.저는 입사한 뒤 갓 신입일 무렵부터 패션 버티컬 앱, 셀렙샵을 처음부터 만드는 프로젝트에 참여하게 되었습니다.새로운 것을 시도할 수 있다는 설렘은 모두에게 전해져서, 모든 팀원들이 열정적으로 여러 프레임워크와 아키텍쳐를 알아보았습니다 (저는 따라가기만 해도 벅찼.. ㅎ).기존 CJ 온스타일 iOS앱은 나름 클래식?한 구조를 따르고 있었습니다.애플이 Swift를 처음 발표할 때 장려한 MVC 패턴Delegate 패턴을 통한 객체 간 통신, NotificationCenter를 이용한 1:n 상태/이벤트 공유Completion Closure를 활용한 비동기 동작하지만 시간이 지나며 반응형 프로그래밍 패러다임과 MVVM, VIPER 등 새로운 아키텍쳐 패턴이 등장했고, 개발자 경험과 모듈화를 위한 다양한 패키지들도 등장했습니다.셀렙샵은 하입뽀이가 되고 싶었습니다.이에 따라 Tuist, RxSwift, ReactorKit, Moya 등 대규모 신기술을 도입했지만, 이 중 RIBs 아키텍쳐를 도입하게 된 이유를 중점적으로 이야기해 보고자 합니다.직접 개발해 보며 느낀 것 위주로 작성하느라 틀린 부분이 있더라도 양해 부탁드립니다.왜 MVC는 더 이상 권장되지 않을까인터넷에 MVC 패턴의 문제점을 검색해보면 View와 Model 사이의 의존성이 높아서 유지보수가 어렵다고 합니다. 저는 사실 무슨 소리인지 이해 못했습니다.제 뇌피셜이지만, 빈 화면에 ‘int main() { return 0 }’ 하나 딸랑 있던 시절 클라이언트 프로그램을 짜려면 직접 View, Controller, Model을 분리해서 MVC패턴 구조에 맞게 직접 만들어 썼던 것 같습니다. 하지만 요즘 모바일 앱개발 프레임워크들은 개발을 쉽게 하도록 각 역할을 추상화 해놨고, 이는 고전적인 MVC 패턴의 구조도와 꽤나 다른 것 때문에 와닿지 않았던 것 같습니다.개중 iOS의 UI Kit은 View와 Controller가 강하게 결합된 구조로, ViewController라는 클래스에 UI와 해당 UI와 관련된 비즈니스 로직을 모두 넣어야 하는 구조입니다.그래서 사실상 M+V+C 패턴이 아닌 M+VC 패턴이 되며, 두 가지의 문제가 생겼습니다.1. 앱 규모가 커질수록 각 ViewController 클래스가 어마어마하게 커진다.이 때문에 앱에서 핵심적인 기능을 하는 1~2가지의 ViewController가 너무 커져서 거의 Monolithic 구조가 되어버리는 현상이 생겼습니다.2. 뷰에 종속되지 않고, 비즈니스 로직만 있는 부분을 따로 관리하기 어렵다.이 문제로 인해 싱글턴 패턴의 Manager 클래스의 남용이 야기됩니다.이 외에도 다양한 문제를 유연하게 대처하고, 재사용성이 높은 아키텍쳐 패턴을 찾다 RIBs에 도달했습니다.RIBs의 구조RIBs TreeRIBs 아키텍쳐는 각 모듈을 트리 형태로 연결한 구조 입니다. 각 모듈은 RIB 혹은 RIBlet이라고 부릅니다. 상태나 이벤트에 따라 하위 립을 뗐다 붙였다 할 수 있습
ribs
매스프레소
RIBs에 ReactorKit 도입하기
안녕하세요! 매스프레소에서 iOS Developer로 일하고 있는 Haskell입니다.매스프레소에서 QANDA를 개발하면서 기존 사용하고 있는 RIBs 아키텍처에 ReactorKit를 도입하게 된 이야기를 해보려고 합니다.RIBs X ReactorKit도입하게 된 이유ReactorKit를 도입을 검토할 당시 iOS팀의 구성원은 5명으로 각자 다른 TF에 소속되어 TF내에서 진행하는 iOS 개발 업무를 담당하고 있었습니다. RIBs를 기반으로 앱을 개발하면서 전체적인 구조는 통일되어 있었지만, 하나의 RIB을 개발하는 방식은 개발자마다 다른 방식으로 구현되어 다른 개발자가 개발한 RIB을 수정하기 위해서는 어떤 방식으로 개발 되었는지 파악하는 일이 선행되어야 했고 이는 생산성 저하로 이어졌습니다. 그와 함께 RIB안에서 상태 관리도 제각기 다른 방식으로 되어 있었기 때문에 Unidirectional data flow와 RIB 구현 방식의 통일된 가이드가 필요한 상황이었습니다.이를 위해 Interactor와 View(Presenter 혹은 ViewController)와 데이터 바인딩을 통해 MVVM과 유사한 방식으로 Unidirectional data flow를 구현하기로 하였습니다.이전에 Flux 개념이 적용된 MVVM 방식으로 개발했던 경험과 ReactorKit를 사용하여 개발을 진행했던 경험을 토대로 어떤 방식으로 Unidirectional data flow를 구현할지 고민하였고 아래와 같은 이유로 ReactorKit를 도입하는 방향으로 진행하였습니다.일관된 구조를 가지고 있어 코드 파악이 기존보다 개선됨.상세한 README와 여러 예제 프로젝트들로 인해 새로 팀에 입사하는 개발자도 적응 하는데 도움이 됨.유지보수가 잘 이루어지고 있음.프로토콜 기반으로 RIBs에도 적절하게 적용 가능여러 회사가 실제 프로덕트 개발에 사용하고 있음.실제 프로젝트에 적용하기까지RIBs를 사용하면서 RIB 단위로 개발을 하고 있기 때문에, 단순하게 ReactorKit를 그대로 도입하여 View마다 Reactor를 생성하여 개발을 하기보다는 RIBs에 맞는 방식으로 ReactorKit를 도입하고자 하였습니다.iOS 개발자 커뮤니티를 통해 실제 이미 RIBs와 ReactorKit를 함께 사용하고 있는 카카오 뱅크 등 여러 회사 개발자분들의 조언을 구하고 개인적으로는 샘플 프로젝트를 개발하면서 실제 개발 시 고려하여 할 점은 무엇인지 고민을 하며 현재 QANDA 프로젝트에 맞게 적용하였습니다.Uber RIBsRIBs의 구성 요소는 아래와 같습니다.https://github.com/uber/RIBs/wiki이런 구성 요소에서 우버가 사용하고 있는 Data flow는 아래와 같으며 이를 참고하여 샘플 프로젝트 개발을 진행하였습니다.Data flow in RIB상세 구현ReactorKit은 View에서 액션이 발생하면 Reactor가 이를 처리하여 State를 업데이트하고 View에서는 필요한 State를 binding하여 State가 업데이트됨에 따라 View를 업
reactorkit
ribs
매스프레소
RIBs Architecture 도입 시리즈 1편: RIBs란?
총 4개의 스토리이며 1. iOS RIBs Architecture 에 대해서는 RIBs에 간략한 설명과 함께 예제를 전체적으로 살펴보고2. RIBs Builder , 3. RIBs Interactor, 4. RIBs Router 에서는 RIBs의 각 구성요소별로 자세히 알아보겠습니다.RIBs는 Router, Interactor, Builder의 약자입니다.하나의 RIB는 Router, Interactor 및 Builder가 필수적으로 구성되고, 필요에 따라 Presenter와 View로 구성됩니다.Builder : RIBs의 모든 구성요소를 생성하고 DI를 정의합니다. 즉, Router, Interactor, View, Component를 모두 생성합니다.Component : 부모 RIB Builder가 Component를 통해 자식 RIB Builder로 의존성을 주입시켜줍니다.Router : 자식 RIB를 attach, detach하여 RIBs 논리적 트리 구조를 형성합니다.Interactor : 비즈니스 로직을 수행하여 Router로 Routing call 그리고 RIBs의 attach와 detach를 요청하거나, Presenter로 Data model를 전달합니다.View : UI화면을 생성하고 구성하여, UI Event를 Presenter로 전달하거나 View model을 받아서 UI를 업데이트합니다.Presenter : Interactor와 View간의 통신을 담당하여 Business model을 View model로 변환하는 역할로 상태를 가지고 있지 않은 클래스입니다. Presenter를 생략하는 경우 View model 변환의 책임은 View 또는 Interactor가 되어야합니다.필요에 따라 Presenter와 View가 구성된다의 의미는, VIPER 패턴과 달리 View가 포함되지 않고 비즈니스 로직으로만 구성된 Viewless RIB의 생성이 가능하다는 의미입니다.RIBs는 논리적 트리 구조를 형성하여, 부모 RIB와 자식 RIB 간 통신을 합니다.RIBs간의 통신은 Interactor가 담당합니다.부모에서 자식으로의 통신은 Observable stream을 넘겨주어서 데이터를 전달합니다.자식에서 부모로의 통신은 자식 Interactor에서 부모 Interactor을 Listener 인터페이스로 접근하게 됩니다.다음은 간단한 RIBs 예제를 보도록 하겠습니다.상기 2개의 이미지는 작은 이미지를 보여주고 있는 ImageViewController 에서 Show detail image 버튼을 클릭하게 되면, 큰 이미지를 보여주는 ImageDetailViewController을 Modal로 띄우는 화면입니다.이 형태를 2개의 Viewable RIB를 통한 RIBs 예제로 살펴보도록 하겠습니다.작은 이미지를 보여주는 ImageRIB와 커다란 이미지를 보여주는 ImageDetailRIB 가 존재합니다. ImageRIB 가 부모 RIB고 ImageDetailRIB 가 자식 RIB입니다.RIBs에서는 부모, 자식 트리 설정 및 해
ribs
매스프레소
RIBs Architecture 도입 시리즈 2편: Builder
이번 스토리에서는 RIBs의 Builder에 대해서 다루어보겠습니다.RIBs에서 Builder는 필수적인 구성요소로서, RIBs의 구성요소인 Router , Interactor , Presenter , View 를 생성하고 자식 Interactor에서 부모 Interactor를 Listener 인터페이스로의 연결을 구성하고 Router를 Output으로 반환하게 됩니다. 또한 RIB 간의 의존성 주입 구성을 책임지게 됩니다.Builder에서 사용하는 RIBs의 기본 클래스들은 다음과 같습니다.기본적인 Builder 역할을 위하여 사용하는 프로토콜 Buildable 과 클래스Builder 가 있습니다.의존성 주입을 위하여 사용하는 프로토콜 Dependency 와 클래스 Component 가 있습니다.Buildable은 선언부 없이 비어있는 class only protocol입니다.BuilderBuilder는 Buildable 프로토콜을 구현하고 있으며, GenericType인 DependencyType의 인스턴스를 생성자에서 주입받도록 정의되어있습니다.DependencyDependency도 Buildable과 같은 형태인 선언부 없이 비어있는 class only protocol입니다.ComponentComponent도 Builder와 같은 형태인 Dependency 프로토콜을 구현하고 GenericType인 DependencyType의 인스턴스를 생성자에서 주입받도록 정의되어있습니다.예제의 RIBs Tree는 다음과 같습니다.Tree 중간에 위치한 ImageRIB의 Builder인 ImageBuilder 위주로 알아보겠습니다.ImageRIB의 View에 해당하는 ImageViewController 화면입니다. 해바라기 이미지를 화면 중앙에 보여주고 있고, Show detail image 버튼이 위치하고 있습니다.해바라기 이미지는 RootRIB로부터 의존성 주입을 통하여 받게 되며, 주입받은 해바라기 이미지를 ImageDetailRIB에 의존성 주입을 통하여 넘겨주게 됩니다.기존 RIBs Tree에 Image 의존성 주입 그래프를 추가하면 다음과 같습니다.RootRIB는 ImageDependency 인터페이스로 ImageRIB에 의존성 주입을 하게 되고, ImageRIB는 ImageDetailDependency 인터페이스로 ImageDetailRIB에 의존성 주입을 하게 됩니다.하기 코드는 ImageRIB의 Builder인 ImageBuilder의 구현부이며, ImageBuilder.swift 코드를 부분적으로 살펴보도록 하겠습니다.먼저 Builder의 역할 중 하나인 의존성 주입 구성이 어떻게 이루어지게 되는지 알아보겠습니다.ImageBuilder는 Builder<ImageDependency>와 ImageBuildable를 구현하고 있습니다.Builder<ImageDependency>에서 사용하는 ImageDependency 의 구현부입니다.ImageDependency 선언부에는 ImageRIB에서 필요한 의존성을 선언합니다. 즉 부모 R
ribs
Copyright © 2025. Codenary All Rights Reserved.