인스타그램이 React Native로 앱을 만든 과정

React Native at Instagram

인스타그램 엔지니어링 블로그에 올라온 “React Native at Instagram”을 번역한 글입니다.

이해를 돕기 위해 몇 가지 간단한 사실을 미리 언급하고자 합니다.

  • 인스타그램 앱은 여러 프로덕트 팀이 협업해서 만듭니다. 글을 읽다보면 굵직한 기능별로 팀이 따로 있는 것처럼 보입니다.
  • 인스타그램을 전혀 사용하지 않아서 서비스를 기술하는 부분에 있어 틀린 부분이 있을 수도 있습니다.

React Native는 2015년 오픈소스로 공개된 후 먼 길을 걸어왔다. 2년 남짓한 시간 동안 React Native는 페이스북과 페이스북 광고 매니저(Facebook Ads Manager)는 물론 포천 500대 기업부터 뜨는 신생 스타트업까지 많은 기업에서 사용되고 있다.

개발 속도는 인스타그램 모바일 엔지니어링의 중요한 부분이다. 우리는 2016년 초에 React Native를 시험해보기 시작했다. 컴파일-설치 과정을 없애주는 Live Reload, Hot Reloading 같은 도구를 사용해서 코드를 공유하고 개발 주기를 빠르게 반복하여 프로덕트팀이 기능을 더 빠르게 추가할 수 있도록 하기 위해서였다.

문제점

React Native를 기존 네이티브 앱에 통합하려면 앱을 바닥부터 만들 때는 겪어보지 못한 문제가 생기거나 추가 작업을 해야할 수 있다. 이 때문에 우리는 우리가 생각할 수 있는 가장 단순한 뷰, 다시 말해 Push Notification 뷰를 포팅하며 문제를 직접 확인해보기로 했다. 원래 WebView로 구현됐던 뷰라서 최초 실행 시간에 큰 영향이 없을 것으로 판단했다. 게다가 이 뷰는 네비게이션 구조도 많이 필요하지 않았다. UI는 매우 단순했으며 번역은 이미 서버에서 다 됐었다.

안드로이드 메소드 개수

첫 번째 문제는 전체 라이브러리를 가져오지 않은 상태로 React Native를 디펜던시로 추가하는 부분이었다. 전체 라이브러리를 가져오면 바이너리 사이즈가 증가할 뿐 아니라 메소드 개수에도 큰 영향을 미치며(역자 주: 안드로이드에는 한 앱이 사용할 수 있는 전체 메소드 개수에 제한이 있다. 참고 링크), 안드로이드용 인스타그램을 여러 성능 문제를 수반하는 여러 개의 dex로 만들어 버린다(인스타그램은 여전히 dex를 1개만 생성한다!). 그 때 우리는 필요한 뷰 매니저만 선택적으로 가져오도록 하고 따로 추가하지 않아도 되는 라이브러리에 의존하는 뷰 매니저는 우리가 따로 작성했다(역자 주: React Native 코드를 변경해서 기존 앱과 겹치는 라이브러리는 공유하도록 했다는 뜻 같습니다). 결국 React Native는 3500개 정도의 메소드만 추가하는 것으로 마무리 되었다. React Native로 작성된 기능을 위해 자바 메소드를 작성할 필요는 없다시피 했으므로, 이 정도 투자는 장기적으로 봤을 때 충분히 가치가 있다고 생각한다.

지표

Push Notification 설정 실험 과정의 하나로, 우리는 앱 강제 종료, 메모리 부족 등 다양한 측면에서 React Native의 영향을 추적했다. 살펴본 결과 사용자가 React Native로 작성된 기능을 떠날 때 계속 유지된 브리지 인스턴스에서나, 초기 실험에서 모두 지표는 안정적이었다. 브리지 인스턴스를 유지하는 이유는 사용자가 다음 번에 다시 해당 기능에 들어와도 인스턴스를 새로 만들지 않아도 되기 때문이다.

최초 실행 성능

React Native의 최초 실행 부하는 거의 JavaScriptCore에 JavaScript 번들을 넣는 부분(JavaScriptCore는 React Native가 iOS와 안드로이드 양쪽 모두에서 사용하는 VM이다) 그리고 네이티브 모듈과 뷰 매니저를 인스턴스화 하는 부분에서 발생한다.

React Native 팀이 인스타그램 통합의 성능 개선을 위해 많이 노력했지만 우리는 이러한 성능차가 우리가 충분히 감내해도 될만한 수준인지 알고 싶었다. 그래서 우리는 기존에 있던 네이티브 Edit Profile 뷰를 React Native로 포팅했다. 그러면서 프로덕트팀이 사용하기 시작한 프로덕트 구조를 동시에 작성했다(예. 네비게이션, 번역, 코어 컴포넌트).

우리는 React Native 팀이 작성해 둔 아이디어와 구조, 다시 말해 Random Access Module Bundling, Inline Requires, Native Parallel Fetching을 비롯해 이미 React Native에 포함되어 있는 많은 것들을 활용했다.

제품

앞서 말했듯 Core Client 팀은 Push Notification 설정과 Edit Profile 뷰를 React Native로 포팅했다. 우리는 또한 Photos Of 뷰도 포팅하여 React Native를 사용해 목록을 표현할 때 성능은 어떤지 알아보고자 했다.

여기에 덧붙여서 여러 프로덕트 팀이 React Native로 기능을 작성하고 있다.

글 홍보

인스타그램에는 Post Promote라고 하는 글을 홍보하기 위한 가벼운 인터페이스가 있다. 이 프로덕트는 네이티브 코드보다 빠르게 개발 주기를 반복할 수 있는 WebView로 작성됐었다. WebView의 문제는 UX가 네이티브처럼 느껴지지 않으며 초기 실행 속도가 너무 느리다는 것이다. Promote 팀은 이 기능을 React Native로 포팅하였고 덕분에 초기 실행 시간과 사용자 경험에 있어 극적인 개선을 이루었다. 이 과정은 매우 복잡했지만 충분히 가치있었으며, 안드로이드 DEX에도 6개의 메소드만 추가했다.

저장

매달 6억 명 이상이 인스타그램을 방문하여 각자의 커뮤니티 속에서 취향에 따라 풍요로운 영감(inspiration)을 발견한다. 하지만 어떤 이들은 영감을 발견한 순간에는 준빈가 되어있지 않아서, 나중에 자신이 준비되었을 때 해당 콘텐츠를 다시 보고 싶어하곤 한다. 이러한 요구에 맞춰, Save팀은 게시물 저장 기능을 만들고 사용자들이 프로필 페이지에서 자신에게만 보이는 탭을 통해 언제든 원할 때 해당 게시물에 접근할 수 있도록 했다.

Save팀은 저장된 게시물 목록을 React Native에서 iOS 버전으로 구현했다.

체크포인트

체크포인트는 의심스러운 행동이 감지되면 서버에서 발생하는 작업 흐름이다. 예를 들어 전화 번호 인증을 요구하거나, 사용자의 계정이 위험에 처해있다고 판단할 때 등이 있다.

과거에 체크포인트는 웹뷰로 구현되었다. 앞서 말했듯이 웹뷰는 코드를 공유하고 빠르게 반복하는 데는 좋지만 UX가 네이티브처럼 느껴지지 않으며 초기 구동 시간이 느릴 수 있다.

Protect팀과 Care팀은 이러한 작업 흐름 일부를 완전히 새롭게 작성하기 시작했다. 두 팀은 React Native를 사용하여 코드 공유의 이점을 누리면서도 훌륭한 사용자 경험과 빠른 초기 구동 시간을 확보하기로 했다.

댓글 관리

우리는 인스타그램이 누구나 자신들의 중요한 순간을 캡쳐하고 공유할 수 있는 안전한 공간이기를 원한다. 인스타그램 커뮤니티가 증가하고 전 세계 곳곳의 사람들이 더 많은 콘텐츠를 공유함에 따라, 우리는 인스타그램을 긍정적이고 안전한 공간으로 만들어 주는 것들을 유지하고자 열심히 일했다. 특히 사진과 동영상의 댓글과 관련해 많이 애썼다. 이러한 목표를 가지고 Feed팀은 사용자가 자신의 글에 있는 댓글을 관리할 수 있는 기능을 추가했다.

Lead Gen Ads

Lead Gen Ads는 사용자가 광고와 함께 정보를 공유할 수 있도록 허용하는 작업 공간이다. 광고주들은 이 작업 공간의 형태를 커스터마이징 할 수 있다.

결과

React Native는 프로덕트팀이 기능을 iOS와 안드로이드 앱에 더 빠르게 추가할 수 있도록 도와주었다. 아래 목록은 특정 기능에 대해 두 앱이 공유하고 있는 공유된 코드의 퍼센트를 보여준다. 개발 속도를 얼마나 개선했는지 짐작할 수 있는 지표가 될 것이다.

  • 글 홍보: 99%
  • SMS Captcha 체크포인트: 97%
  • 댓글 관리: 85%
  • Lead Gen Ads: 87%
  • 푸시 알림(Push Notification) 설정: 92%

댓글을 남겨주세요