안녕하세요 라이더스개발팀 박민 입니다.
배민라이더스의 라이더분들이 배달을 수행하기 위해 사용되는 애플리케이션 ‘라이더스’ 개발기를 적어보려 합니다.

라이더스란?

먼저 BROS(Baemin Riders Operating System)가 있습니다. (네! Geo-fence를 신선하고 유익하게 설명해주신 민철님의 글에서도 등장합니다.) 라이더스는 BROS에서 발생하는 배달을 라이더가 수행할 수 있도록 배차 요청을 비롯해 픽업, 전달 등의 배달업무를 처리하는 애플리케이션입니다. 플랫폼의 이름과 같은 Android 버전에서의 ‘BROS’에서 직관적인 이름의 ‘라이더스’로 변경되었습니다.

iOS 버전의 라이더스는 왜 필요했을까요?

늘어나는 주문을 처리하기 위해 우리는 많은 라이더분이 필요합니다. 그래서 모집공고를 통해 많은 예비라이더 분을 뵙게 되는데, 10명 중 2명은 아이폰을 사용하시기에 OS의 문턱에 발걸음을 돌리셨다고 합니다.(물론 업무용으로 따로 Android기기를 사용하시는 분도 계십니다.) 20%의 수치는 현재 아이폰 사용률, 특히 젊은 층의 사용률을 미루어 보았을 때 앞으로 더욱 높아질 수 있다고 생각했습니다. 그래서 우리는 앞으로 더 많은 예비라이더 분들을 놓치지 않기 위해 iOS 버전의 라이더스가 필요했습니다.

그럼 이제 만들어보겠습니다..만

iOS 버전 라이더스의 필요성은 충분히 공감했지만 저는 iOS 애플리케이션을 만들어 본 적이 한 번도 없었고, 하물며 우아한형제들과 일하게 되며 맥북을 처음 사용했습니다.(#새맥북#좋은개발환경) 그런 제게 Object-C, Swift는 낯설기만 했고 벽은 높아만 보였습니다.

React Native로 시작하게 된 계기

  1. 라이더스는 단순한 기능을 수행하는 애플리케이션입니다.
    • 소켓을 통해 생성된 배달을 수신합니다.
    • 이후에는 API 요청을 통해 배달업무를 수행합니다.
    • 위치 수집을 해야 하고, 지도페이지 등이 있지만 간단한 애플리케이션입니다.
  2. React는 가볍게 경험해봤습니다.
    • 과거에 PC 프로그램을 만들기 위해 React와 Electron을 사용한 경험이 있었습니다.

네이티브로 만드는 것이 닿지 않을 듯 멀게만 느껴지고, React Native가 힙해 보여서 사용하게 된 것은 아니었습니다.
선택에는 위 2가지 이유가 있었고, 우선 React Native로 개발 가능 여부를 빠르게 검토하고, 안 되겠구나싶으면 Object-C, Swift를 배워야겠다! 하는 마음으로 시작했습니다.


누가 시켜서 한건 절대로 아니에요. 다만 @재일님께서 해보라고 ‘권유’는 하셨습니다. ~(^^~)

React Native 개발기

React Native의 동작

자바스크립트가 네이티브에서 동작하기 위해서는 네이티브 코드가 필요합니다.
버튼을 예로 들어보겠습니다.
먼저, 자바스크립트에서 버튼을 구성하고 네이티브에서의 버튼 기능을 수행할 컨트롤 과 bridge로 통신하면 됩니다.


잠깐만요? 네.. 네이티브의 벽은 높지만 구현 해야 합니다.

물론 React Native는 네이티브 경험 없이도 애플리케이션을 만들 수 있는 매력적인 플랫폼입니다. 그리고 화면 구성을 위한 정말 다양한 컴포넌트가 (Button,RefreshControl,WebView 등) 이미 제공되기 때문에 네이티브 개발을 줄여주고, 빠른 애플리케이션 개발을 도와줍니다.

하지만 간단한 애플리케이션인 라이더스에서도 React Native가 제공하는 컴포넌트 이외의 화면이 필요했습니다.(간단하게는 지도화면부터, 애플리케이션을 환경(live, beta)별로 관리하거나, build를 할 때 필요한 네이티브의 설정들을 제공하는 네이티브 모듈들이 필요했습니다.)
그리고 만약 저처럼 제공하지 않는 컴포넌트로 화면을 구성하기 위해서는 보통 2가지 방법이 있습니다.

  1. 라이브러리를 찾습니다. 없으면 기다린다. 누군가 만들어 주실 때까지..
  2. 직접 구현합니다.

React Native는 네이티브 개발의 필요성을 줄여주지만, 여전히 네이티브 개발이 필요합니다. 그래서 네이티브 경험 없이 애플리케이션을 개발하는 것은 힘들게 느껴질 수 있겠지만, 오히려 제게는 네이티브를 통한 간편한 확장성이 React Native를 쉽게 선택할 수 있게 하는 장점이라고 생각합니다.(이가 없으면 잇몸으로!)

React Native의 개발과정

React Native로 개발하며 흥미로웠던 부분은 네이티브와는 다른 React Native의 개발과정이었습니다.
예를 들어 네이티브의 경우에는 테스트 디바이스에 애플리케이션을 설치하고 확인하고, 다른 해상도의 테스트 디바이스에 설치하고.. ‘엇 어긋나네..?’ 수정하고, 다시 설치하고, 이전 기기에 또 설치하고.. 확인하고.. x100
React Native는 로컬의 노드 서버에서 published JavaScript 코드를 수행합니다. 그렇기 때문에 에뮬레이터를 비롯한 실제 디바이스에서의 변경사항 확인은 애플리케이션의 컴파일 없이 새로 고침으로 충분합니다.

조금만 자세하게 설명해보겠습니다

  • React Native는 <react-native run 'platform'> 명령어를 통해 프로젝트를 구동하면 먼저 로컬에 index.platform.bundle을 게시하는 노드 웹서버를 실행합니다.
  • 그 다음 platform에 해당하는 iOS/Android 프로젝트를 빌드하고 에뮬레이터 혹은 디바이스에 설치됩니다. 이 프로젝트에서 로컬에 구동된 index.platform.bundle을 다운로드 받습니다.
  • 다운로드 후에 React Native 빌드 프로세스를 통해 JavaScript 런타임 환경으로 전달되어 프로젝트가 구동됩니다. 이후부터는 JavaScript의 수정이 생기면 새로 고침만으로 변경사항을 확인할 수 있습니다.
  • 그렇기 때문에 여러 대의 기기에 한 번 설치 후에는 다시 컴파일이 필요 없이 변경사항을 확인할 수 있습니다.
    특히 여러 디바이스에서 확인이 필요한 디자인 QA를 진행할 때 가장 큰 장점이 아니었나싶습니다.
  • 또한 이 기능을 통해 Code Push를 사용하여 이미 배포된 애플리케이션의 재배포 없이 JavaScript 수정이 가능합니다.

혹시 네이티브 영역의 코드가 변경되야한다면! 네.. 다시 패키징하는 방법으로 배포해야합니다.

React Native로 개발하기 위해서

앞서 말씀드린 것처럼 네이티브의 지식도 필요합니다. 그래서 iOS 경험이 없던 저는 Object-C도 함께 학습해야 했지만
제 생각에는 React에 대한 학습이 좋은 애플리케이션을 만드는데 더 많은 영향을 미치는 것 같았습니다.
서비스에 따라 네이티브의 영향이 큰 프로젝트도 많겠지만, 라이더스의 경우에는 빈번한 화면 render와 화면 전환이 중요한 부분이었고, (지도를 제외한 모든 화면이 React로 구성되었습니다.) 특히나 사용자에게는 네이티브로 개발된 Android 버전의 라이더스BROS가 비교 대상이었기 때문에 그만큼의 퍼포먼스가 요구되었습니다.

효율적인 React Native 애플리케이션 만들기

React는 setState() 메서드를 통해 컴포넌트를 표현할 때 사용하는 state를 업데이트할 수 있습니다.
setState() 메서드가 수행되면 컴포넌트에 Dirty로 마크되고, 다음 이벤트 루프 때 Dirty 컴포넌트를 다시 render하게 되는데, 이때 Dirty 컴포넌트의 하위 컴포넌트까지 render의 대상이 됩니다.

컴포넌트를 표현하기 위한 state의 잦은 변경은 자칫 불필요하게 빈번한 화면 render를 수행하게 할 수 있습니다. 이를 효율적으로 처리하기 위해서는 적절한 shouldComponentUpdate를 활용해야 합니다. shouldComponentUpdate는 render가 수행되기 전에 render 필요 여부를 return 하는 React 생명주기의 일부입니다.

물론 React에서는 shouldComponentUpdate를 이미 구현한 pureComponent도 제공을 합니다. 하지만 이 컴포넌트는 변경된 props와 state를 shallow level에서 비교한 결과로 render 여부를 판단하기 때문에 의도하지 않은 render가 발생할 수 있습니다.

만약 직접 shouldComponentUpdate를 구현한다면 주의할 점이 있습니다.
컴포넌트가 커지면 자연스럽게 사용되는 props와 state가 다양해집니다. 그렇다 보면 shouldComponentUpdate에서의 정확한 render 여부를 반환하기 위해 props와 state의 deep-compare 유혹에 빠지게 될 때가 있습니다.

하지만 shouldComponentUpdate에서 deep-compare는 권장되는 행동이 아닙니다. we don’t recommend deep equality checks
요약해보면, shouldComponentUpdate에서 render 하지 않겠다고 판단하는 데 소비하는 시간이 render 하는 시간보다 길어질 것을 우려하기 때문입니다. 제 경험으로는 효율적인 render를 위해서 무엇보다 각 컴포넌트를 목적에 따라 작게 나누고, 컴포넌트는 필요한 props와 state만 다루는 것이 결국 render가 수행되어야 하는 시점을 쉽게 판단할 수 있도록 해주었습니다.

라이더스 개발에 필요했던 라이브러리들

다음은 라이더스를 만들며 사용한 React Native의 API와 유용한 라이브러리를 소개합니다.

  1. 네트워크
    • fetch API를 지원합니다.
    • 라이더스의 핵심이라 할 수 있는 WebSocket도 지원합니다.
  2. 위치수집
    • React Native는 Geolocation API를 제공합니다.
    • 이 API는 import 없이 navigator.geolocation로 사용가능합니다.
  3. 기타 라이브러리
    • react-redux
      • state를 관리해주는 도구이며, 많은 분이 알고 계시는 FLUX 패턴을 편하게 사용할 수 있게 도와주는 라이브러리입니다.
      • 라이더스에서는 라이더가 WebSocket으로 수신하는 메시지에 따라 변경되는 데이터의 상태에 접근하고 상태에 따라 화면을 변경하기 위해 사용되었습니다.

        redux
        • store, dispatch, action, reducer가 있습니다.
        • store의 데이터를 변경하기 위해 action을 dispatch 해야 하는데, 그것을 받아 처리하는 함수를 reducer라고 합니다.
        • action은 데이터의 변화를 알려주는 객체이며, reducer는 그 객체로 애플리케이션의 state를 어떻게 바꿀지 정의합니다.

    • redux-thunk
      • 비동기 처리 작업을 도와주는 미들웨어입니다. [정말 단순한 구현체입니다]
      • redux-thunk는 dispatch된 action이 함수라면 dispatch와 getState를 함께 전달합니다. 이로써 전달된 함수 내부에서는 여러가지 일을 할 수 있게 됩니다. 네트워크 작업 등을 통해 여러번 dispatch가 수행 될 수 있습니다.

        미들웨어
        • action과 reducer의 중간에 존재합니다
        • reducer가 dispatch된 action을 처리하기 전에 작업을 수행하기 위한 중간자 역할입니다.

    • react-navigation
      • 애플리케이션에서 필요한 화면전환을 제공합니다.
      • 화면전환 뿐 아니라 여러 편리한 기능을 제공하는 react-native-navigation 라이브러리도 있습니다.

개발기를 마치며

많은 이야기를 하고 싶은 마음과 절제하려는 열 손가락 사이에서 두서없는 글이 탄생하게 되었습니다. ㅠ_ㅠ
처음 개발 시작할 때 함께한 우려와 머뭇거림이 아직 프로젝트 곳곳에 고스란히 묻어있지만 이미 React Native로 개발된 iOS 버전의 라이더스는 릴리즈 되었고, Android 버전도 준비 중입니다.

[React Native를 검색할 때 tutorial과 앞다투는 검색어]

위 사진 속 우려의 검색어가 시작할 때 저를 주춤하게 한 가장 큰 걸림돌이었습니다. 만약 React Native를 시작하려 하시는 분이 계신다면, (추천하기에는 저는 아직 많이 배워가는 단계지만) 그저 애플리케이션을 개발하는 방법이 하나 더 생겼다는 마음으로 가볍게 마주하면 어떨까 싶습니다. 서툰 글을 읽어주셔서 감사합니다. 그리고 도움 주신 동료 iOS 개발자분들께 많은 감사드립니다.


참고 사이트