Conomi App ReactNative -> Native 전환과 관련된 이야기

Eunchul Jeon
네이버 플레이스 개발 블로그
18 min readJul 12, 2021

--

일본에서 운영중인 Line Conomi 서비스

안녕하세요. Naver Glace CIC에서 Conomi App 개발하고 있는 전은철입니다. 저희는 지난 6월에 App버전 2.13.0에서 ReactNative 기반으로 동작하던 App을 Native로 전환하였습니다. 전환하는 과정에서 고민했던 부분이 몇가지 있어서 해당 내용을 간단하게 정리해봤습니다.

개인적인 의견이지만, Cross Platform으로 App을 구성하려는데

  • 팀이 Web base, 또는 Web Mobile 을 하나의 기술 스택으로 가고싶으면 ReactNative 를 선택
  • 팀이 Mobile Base로 빠르게 앱만 진행하고 싶으면 Flutter 선택

또한 저희는 ReactNative 앱을 Native앱으로 전환했지만, 반드시 Native App으로 전환해야 한다고 생각하지 않습니다.

  • 일부를 ReactNative, 일부는 Native로 가는것은 개발상으로나 운영상으로 문제점이 있습니다. 최상위에 존재하는 RCTRootView가 무거워서 여러개를 띄우기 적합하지 않고, 개발 및 운영시 커뮤니케이션 비용도 추가로 발생합니다.
  • 팀내에 Native App 개발자수가 많아져서, Native 개발자를 ReactNative 개발자로 전환시키는것보다 Native로만 화면을 개발을 하는것이 더 빠르게 스펙을 소화할 수 있는 상황이 되었습니다.
  • 가능한 많은 RN 화면을 한번에 제거하기 위해 RN 화면을 Web으로 전환하고, 동시에 Native로 전환하였습니다.

Cross Platform은 해야하는가?

저는 지금은 Conomi App을 개발하고 있지만 2년전에는 STEP 이라는 서비스를 개발하고 있었습니다. 해당 서비스는 비즈니스 측면에서 어느정도 Conomi 서비스와 차이가 있겠지만, 앱개발자 입장에서 개발적인 측면에서 봤을 때, 사업에서 요구하는 기능들이 크게 다른 앱은 아니었습니다.

  • 유저는 본인의 이미지와 동영상을 간단하게(?) 편집하고 업로드한다.
  • 유저가 업로드한 컨텐츠는 My 탭에서 확인 할 수 있다
  • 팔로워/팔로잉, 좋아요, 태그 기능등이 있다.
  • 팔로워/팔로잉, 좋아요를 기반으로 피드를 구성한다
  • 검색이 되어야하고, 검색시 자동완성과 적절한(?) 알고리즘을 통해 추천이 이루어진다.

그리고 저는 2015년에는 동일한 요구사항을 가진 폴라(Pholar) 라는 서비스를 사내에서 개발했었습니다. 동일한 기능을 가진 서비스지만, 폴라와 STEP의 경우 iOS/Android 각각 4명씩 총 8명의 앱 개발자가 개발을 진행하였고, 요구사항에 맞춰 잘 개발을 했지만 사업적인 돌파구를 찾지 못하고 둘다 서비스를 종료하였습니다. Conomi의 경우 동일한 기능을 서버/웹 개발자 중심으로 ReactNative 기반으로 개발하였고, 현재 3년째 운영하고 있습니다.

단편적인 예이기 때문에 Native 또는 Cross Platfrom 으로 개발하는것이 사업의 요구사항을 빨리 meet 할 수 있고 운영에 적합하다라는것 보다는, 동일한 기능을 Cross platform 으로 개발하면서 일부 필수적인 부분만 native 로 구현해도 큰 문제가 없다라고 생각 할 수 있을 것 같습니다.

Cross Platform의 장점

Cross Platform 의 장점은 결국 개발 및 운영비용 감소입니다.
이제는 굉장히 오래된 이야기가 되었지만, Facebook 은 2010년 초반에 Native App 개발 대신 공통개발을 위해 HTML5에 투자하였지만 속도 문제가 있었고 결국 다시 Native App 으로 전환하였습니다.
마크 저커버그는 이 결정이 큰 실수 였다고 Tech Crunch 와의 인터뷰에서도 얘기를 했었는데, 지금까지도 적당히 performance 타협을 하더라도 개발비용을 낮출수 있는 방법에 대해 Facebook은 고민을 하고 있고, 이것은 ReactNative로 이어지게 되었습니다.

링크된 포스팅은 ReactNative, Flutter, Native App에서 다양한 애니메이션을 실행하였을때 FPS, CPU, GPU 사용량, Memory, Battery 등을 측정해본 게시물입니다.

성능측정을 위한 View 예시
성능 측정을 위한 View 예시
iOS 디바이스에서 성능을 측정한 결과
Android 디바이스에서 성능을 측정한 결과

위의 표만보면 살짝 오해할수도 있는데, Facebook, Discord, Shopify 등 많은 App들이 ReactNative로 개발이 되었고, 문제없이 운영을 하고 있습니다. 글에서도 일반적인 경우에는 퍼포먼스에 문제가 없다고 얘기하고 있습니다. 해당 결과는 ReactNative의 경우 Javascript -> Native 로 전환하는 과정에서 CPU 사용량이 올라갈수 있다는 것과, Cross platform 기술들이 Native에 비해 메모리 사용량이나 Battery 사용적인 측면에서 최적화가 떨어질수도 있다고 이해하면 좋을 것 같습니다.

Cross platform 이 App의 Performance 측면에서 Native에 비해 떨어진다, 떨어지지 않는다, 떨어져도 유저가 원하는 기능을 제공하는데는 문제가 없다는 논란의 부분이 있지만, 플랫폼별로 코드를 하나로 가져감으로써 생기는 장점은 사실 논란의 여지가 거의 없습니다.

많은 iOS/Android 개발자들이 이건 우리 플랫폼에서는 잘 동작하지 않는다, 이건 iOS스럽지 못하다 Android스럽지 못하다면서 기획자와 논의를 해본 경험이 있을것이고, 기획자의 요청이 iOS만 또는 Android에만 전달된 경험을 모바일 개발자라면 해본 적 있을겁니다. 애초에 동일한 기능을 두벌 개발하는데서 오는 Cost는 작지 않습니다.

저희 Conomi 팀은 원래 ReactNative로 개발하던 인력들이 빠지고, Native 개발자들이 충원되면서 편집 및 작성쪽에만 Native를 사용하던 기능을, ReactNative를 제거하고 전체 Native로 전환하고 있습니다. 현재는 충분한 앱개발자 인력이 있기때문에 ReactNative로 개발하는것보다 Native로 개발을 하는것이 맞다고 생각하지만, 인력상황은 언제든지 변동이 된다고 생각해봤을때는 ReactNative를 유지했어야했나, 혹은 Flutter로 갔어야했나 하는 고민이됩니다.

특히 조직내에서 제한된 유저의 단순한 기능의 앱을 제작을 해달라는 요청이 저에게 온다면,

  • Webview로만 제작
  • Cross Platform으로 제작
  • Native로 제작

셋 중에 어떤것을 택할지는 상황에 따라 Case By Case 일것 같습니다.

Cross Platform의 단점

Major가 되지 못한 Closs platform 은 사장될 가능성이 있습니다.
2010년대 초에도 PhoneGap, WAC, 앱스프레소등 다양한 하이브리드앱 플랫폼들이 있었고 Major 가 되지 못한 하이브리드 앱 플랫폼은 사장되어갑니다.

Cross Platform 을 쓴다는것은 결국 Dependency를 하나 더 추가한다는 의미라, Apple 이 iOS에 버그를 만들면 Patch를 기다려야하듯, 문제가 생기면 운영하는 커뮤니티에서 대응해주기를 기다릴 수 밖에 없습니다.

많은 Cross Platform 언어들 중에서 어떤 언어를 선택해야하는가?

결국은 개발 비용 및 운영 비용이 적은 방향으로

지난달부터 저는 사내의 모바일 기술위원회의 Cross Platform 분야쪽에 논의에 참여하고 있는데,
해당 논의에 참여하고 있는 팀들은 다음과 같은 Cross Platform 을 사용하고 있습니다

  • Conomi App : ReactNative
  • 블로그 지식인: Flutter
  • Works, 스토어회원개발: KMM(Kotlin Multiplatform Mobile)

한가지 재미있는 점은 웹/서버 기반의 개발경험을 가지고 있던 Conomi 팀에서는 ReactNative를, Android 기반의 개발경험을 가지고 있던 Works, 스토어회원개발팀에서는 KMM을, iOS기반의 경험을 가지고 있던 팀에서는 Flutter를 사용하고 있는 점이었습니다.
물론 각 플랫폼별로 한건씩 밖에 안되기 때문에 단순한 우연일수도 있지만, 성능이 더 뛰어날 수 밖에 없는 Native 개발이 아닌 Cross Platform을 선택하는 주된 이유는 개발속도를 향상시키고 운영비용을 줄이기 위한 것이기 때문에, 개발하는 사람의 개발경험을 어느정도 따라가는게 필연일수 밖에 없나하는 생각도 들었습니다.

Phonegap, Xamarin, React Native, Flutter, KMM

Google Trend 검색결과(https://trends.google.com/trends/explore?cat=5&date=all&q=kmm,react%20native,Flutter,xamarin,phonegap)

위의 이미지는 Google Trend 검색 결과인데, 검색량이 Phonegap(HTML5) -> Xamarin(C#) -> React Native(JavaScript) -> Flutter(Dart) 로 이어지는 전반적인 Cross-Platform 의 변화과정을 잘 보여주는것 같아서 재밌는 그래프입니다.

각 플랫폼별 장단점은 이 포스팅에 잘 정리되어 있습니다.

ReactNative vs Flutter

ReactNative와 Flutter 관련해서는 이 영상에서 잘 정리해주고 있는데, ReactNative는 3rd party에 의존적이고, Flutter는 google에 의존적이라는 내용이 가장 중요한 내용같습니다.

ReactNative에서 WebView를 Deprecate 한 document

그렇기 때문에 ReactNative에서는 Webview 같은 중요한 Component 도 deprecate 한 다음에 community에서 대응해주는 component를 쓰라고 권장하고 있습니다.

반면에 Flutter는 Google에 의해서 운영되기때문에 Google의 지원에 의존적일 수 밖에 없습니다.

다음은 Stackoverflow 에서 정리한 가장 사랑받고있는 framework 에 대한 표입니다.

https://insights.stackoverflow.com/survey/2020#technology-most-loved-dreaded-and-wanted-other-frameworks-libraries-and-tools

분위기 자체는 위에 Google Trend 차트에서도 확인할 수 있지만, stackoverflow를 보더라도, 작년을 기점으로 Flutter 쪽이 좀더 우세한 느낌입니다.

Native, Webview base, ReactNative, Flutter 구조

블로그에 각각의 구조에 대해서 설명을 잘해주고 있는데 간단하게만 또 정리해보면

  • Native

iOS, Android 각 플랫폼별로 ObjectiveC, Swift 그리고 Java, Kotlin 으로 된 Native Code 를 이용해서 Platform에서 제공하는 UI Component 에 접근하고, 화면을 구성합니다.

  • Webview base

2010년대 초반에 나온 PhoneGap, Apache Cordova, Ionic 등은 Webview 기반으로 화면을 구성합니다. Native UI Component에 접근하는것 없이 HTML과 Javascript를 이용해서 Webview에 그리고, Location이나 Audio, Camera 등 Native 접근이 필요할때는 Bridge를 통해서 통신합니다. Webview의 속도가 빨라져서 최근에는 Ionic 최신 버전의 경우 60 fps 까지도 나온다는 얘기도 있는데, 한창 유행할때만 해도 Native에 비해 속도차이가 많이 느껴졌었습니다.

  • ReactNative

ReactNative 는 Webview에서 벗어나 Bridge를 이용해서 JSON으로 통신하며 직접 Native UI Component에 접근함으로써 UI를 WebView로 사용하던 전세대 Cross Platform framework들에 비해 빠른 속도를 가지게 됩니다.

하지만 Bridge에서 JSON을 이용해서 통신을 하는 부분에서 속도 저하가 있을 수 밖에 없고, 이 부분을 Fabric과 Turbo Modules를 만들어서 C++ 객체에 접근할 수 있게하고, 필요할때마다 모듈을 불러올수 있게 개선하였습니다.

  • Flutter

Flutter는 iOS, Android 통합을 자체적인 UI Component를 만들고 Dart라는 언어를 사용함으로써 해결했습니다. Native Component 를 구글에서 직접적으로 만들었기 때문에 Native에 가까운 성능을 구현 할 수 있습니다.

ReactNative의 장점

성능만을 놓고 보자고하면, Native 로 앱을 개발해야합니다. iOS Native 개발자들 중에는 파싱하는 시간이 아까워서 Storyboard를 안쓴다는 개발자들도 존재하고, Layout Constraint 계산하는데 걸리는 시간이 아까워서 autoLayout 이라는 기능을 안쓰고 frame을 하나하나 계산하는 개발자 분들도 많습니다. 하지만 속도에 대한 생각을 좀 내려놓고나면, 또 다른 선택들이 있습니다. 이미 많은 Major App들이 ReactNative를 사용하고 있구요

  • Web-iOS-Android 를 하나의 코드로 통합
    하나의 기술 스택으로 web, iOS, Android 를 개발하고 관리 할 수 있다는것은 너무나도 매력적입니다. Web 개발자 4명, iOS개발자 4명, Android 개발자 4명, 이렇게 각각 플랫폼에서 개발하는것 보다 12명의 ReactNative 개발자가 각각 스펙을 맡고 코드리뷰하고, 코드를 관리하는것이 전반적인 개발속도가 더 빠를 수 밖에 없습니다. 기획자는 같은 스펙에 대해 web, iOS, Android에 각각 전파할 필요없이, RN 개발자 한명에게 전파하면 끝납니다. 이것은 앱의 퍼포먼스를 어느정도 포기할 만한 충분한 이유가 되는 것 같습니다.
  • Hot Reloading

지금은 SwiftUI에서 핫리로딩을 제공해서 iOS Native App 개발시에도 핫리로딩이 가능하지만, SwiftUI를 쓰지 않는 환경에서는 여전히 핫리로딩 기능을 사용하기 힘듭니다. 개인적으로는 핫리로딩은 UI 개발속도를 비약적으로 상승시킨다고 생각합니다.

  • CodePush

개발자에게 버그는 피할수 없는 문제이고, iOS의 App Store 리뷰기간없이 자신이 만든 버그를 없앨 수 있다는건 너무나도 매력적인 기능입니다.

ReactNative — Native 개발시 불편한 부분

ReactNative와 Native 가 공존하는 프로젝트

당연한 얘기지만 ReactNative 와 Native 화면이 공존하려면 ReactNative 에서 Native View 를 사용할 수도, 반대로 Native View에서 ReactNative View를 사용할수도 있어야합니다. 전자는 ReactNative 가 일반적으로 동작하는 방식이라 문제가 없지만, 후자의 경우 RCTRootView 라고 하는 JavaScript단과 Native 단을 연결해주는 RCTBridge 를 가지고 있는 객체를 통해 띄워줘야합니다.
RCTBridge 객체가 굉장히 무겁기 때문에 전체 앱에서 하나만을 가지기를 권장하고 있습니다. 여러개의 RCTRootView를 써야하는 경우 이 RCTBridge 를 하나만 만들어서 공유해서 써야하고, 제한적인 갯수의 RCTRootView를 사용해야합니다.

Native 기반으로 Conomi App 을 전환하기 위해서 우선은 많은 화면을 Webview와 Native 기반으로 전환하였습니다.
그리고 최소한의 RCTRootView를 사용하기 위해 Native 화면에 의해 RCTRootView가 가려질때마다 제거 후, 노출 시점에
다시 그려지는 형태로 RCTRootView를 재사용 하였습니다.

Metro Bundler

Metro Bundler 는 Javascript 파일과 리소스 들을 앱단에서 사용할 수 있도록 하나의 파일로 묶어주는 역할을 합니다. 앱을 개발하기 위해서 항상 CLI에서 띄워놔야하고, 앱 시작시 Javascript와 리소스들을 다운로드 받는 과정을 거치게 됩니다.

Debugging 문제

Chrome 개발자 도구를 통해 ReactNative 코드를 디버깅 할 수 있습니다. 하지만 전환하는 과정이 느리고, Native -> RN -> Native 로 주고받는 과정을 디버깅하기가 쉽지 않았습니다.

RN, Webview, Native 화면 각각 개발, 통신 및 Sync 문제

처음에는 작성화면만 Native 였습니다. 카메라를 사용하고, 앨범을 이용해서 사진 및 비디오만 가져오고, 작성하는 부분만 Native로 구성, 서버에까지 업로드 하고나면 Native 화면은 역할을 다하고, App 메모리에서 사라졌습니다.

하지만 점점 많은 화면이 Native 로 전환되면서, 단순히 개발을 왔다갔다하는 문제에서 더 커져서, 각각이 네트워크 모듈, 케쉬 모듈 등을 가지고 있게 되고, ReactNative, Webview, Native 화면이 공존하면서 각 화면에 event 를 전달해야하는 상황이 많이 발생했습니다.

기본적으로 WebView와 Native 의 경우는 PostMessage, RN과 Native의 경우는 Deeplink 를 이용해서 서로 통신을 합니다.

Web쪽에서 Simulator를 만들어주셔서 로직을 공통화 하고 테스트를 쉽게 해볼수 있었지만, 좋아요, 팔로우, 북마크 등 다양한 유저액션이 바로 반영되어 있지 않은 화면이 많이 발생하고 Sync시 Notification에 Cycle이 생기는 경우도 발생하였습니다.

개발 구성원의 변경

가장 큰 변화는 App을 개발하는 주체가 Native App 개발자들이 되었습니다. 기존 화면을 작성해주신 분들이 많이 없는 상황에서, 해당 화면을 유지하는 것보다는 익숙한 Native 로 전반적으로 전환하는것이 더 빨랐고, 일부만 ReactNative 화면을 유지하면서 드는 비용이 점점 더 크게 느껴져 현재는 전체를 Native와 Webview 로 변경하고 있습니다.

결론

때때로 서비스의 생명은 길고, 때때로 짧습니다. 여러해 운영하면서 Objective C로 구현했지만, Swift 로 크게 전환해보기도하고, 많은것을 예상하고 미리 준비해뒀지만 출시하고 3개월만에 서비스를 접어보기도 했습니다. ReactNative 로 개발했지만 Native로 전환을 한 것도 서비스가 유지되었기에 가능한 행복한 고민이긴합니다. 하지만 다음 포인트가 이미 Native로 대부분을 전환한 상황에서 고민으로 남아있습니다.

  • 개발인력은 또 변할 수 있습니다. 지금은 충분한 수의 Native 개발자가 있고, 이 인원이 코노미 앱개발에 투입되어있지만, 상황에 따라 최소의 인력, 또는 Native 개발자가 아닌 다른 백그라운드의 개발자가 Conomi App 개발을 운영해야 할 수 있습니다.
  • 개발자는 상황에 따라 새로운 언어를 쉽게 배울수 있어야하고, Native 개발자가 ReactNative를 배우는것이 불가능한 문제는 아닙니다.
  • 크로스플랫폼의 성능은 계속 좋아지고 있습니다.

참고

--

--