메타, 페이스북 iOS 앱 10주년을 기념하다

10년간 코드베이스 진화 과정 밝혀

컴퓨팅입력 :2023/02/15 11:06

페이스북 iOS 앱이 출시된 지 올해로 10년을 넘겼다. 메타 엔지니어링팀은 이를 기념하며 지난 10년 간 코드베이스를 발전시켜온 과정과 그 속에서 이뤄진 선택의 의미를 설명하는 글을 올렸다.

최근 메타 엔지니어링팀의 더스틴 샤히데푸르 소프트웨어엔지니어는 메타 엔지니어링 블로그에 'iOS용 페이스북(FBiOS)' 앱 아키텍처의 진화를 설명했다.

더스틴 샤히데푸르 엔지니어는 "FBiOS는 메타에서 가장 오래된 모바일 코드베이스로, 2012년 앱을 재작성한 이후 수천명의 엔지니어가 작업하고 수십억 명의 사용자에게 제공됐으며, 한번에 수백명 엔지니어의 이터레이션을 지원할 수 있다"며 그는 "수년의 버전을 거쳐 페이스북 코드베이스는 일반적인 iOS 코드베이스와 유사하지 않게 됐다"고 설명했다.

그는 "10년 간의 진화를 반영하며 작업 엔지니어 증가, 안정성, 사용자 경험 등을 지원하는데 필요한 기술적 결정에 박차를 가해왔다"며 "코드베이스의 10주년을 기념하기 위해 진화의 이면에 있는 기술적 결정과 그 역사적 맥락을 조명하겠다"고 서두에서 밝혔다.

사진=페이스북

그에 따르면, 현재 FBiOS 앱은 C++, 오브젝트C(++), 스위프트 등으로 만들어져있다. 수십개의 동적라이브러리(dylibs)와 한번에 X코드에 로드할 수 없는 수많은 클래스들을 포함한다. 애플 SDK의 원시 사용은 거의 없으며 모든 것을 내부 추상화로 래핑하거나 대체했다. 앱은 메타 자체 빌드 시스템인 '벅(Buck)'으로 코드를 생성한다. 빌드 시스템에서 대량 캐시를 사용함으로써 앱 빌드 대기 시간을 줄였다.

■ 2014년, 리액트와 콤포넌트 UI 프레임워크

모바일 기기용 네이티브 페이스북 앱 출시 후 2년 뒤 뉴스피드의 코드베이스에서 안정성 문제가 발생하기 시작했다. 당시 뉴스피드 데이터 모델은 애플의 기본 데이터모델 관리 프레임워크인 '코어데이터' 지원을 받고 있었다. 코어데이터는 개체를 변경할 수 있고, 뉴스피드의 멀티스레드 아키텍처에 적합하지 않았다. 뉴스피드는 코코아(cocoa)의 디자인 패턴인 '모델뷰컨트롤러'를 사용해 양방향 데이터 흐름을 활용했다.

샤히데푸르 엔지니어는 "이 설계는 디버깅과 재현을 어렵게 만드는 비결정적 코드 생성을 악화시켰다"며 "지속가능하지 않다는 게 분명해지고 다시 생각해야할 때였다"고 설명했다.

그 무렵 당시 페이스북의 한 엔지니어가 자바스크립트 커뮤니티에서 인기를 얻고 있던 오픈소스 UI 프레임워크인 '리액트(React)'를 연구했다. 리액트의 선언적 디자인은 웹 뉴스피드에서 문제를 일으키는 까다로운 명령형 코드를 추상화하고, 단방향 데이터흐름을 활용해 코드를 훨씬 쉽게 추론할 수 있게 했다.

그러나 당시 애플 SDK는 선언적 UI를 갖지 않았다. 스위프트는 없었고, 선언적 UI 프레임워크인 스위프트UI는 2019년에야 나왔다. 이에 엔지니어링팀은 새로운 UI 프레임워크를 구축했다. 수개월에 걸쳐 새 UI 프레임워크로 뉴스피드를 구축하고 이전한 뒤 FBiOS 성능이 50% 향상됐다.

페이브북은 이를 '콤포넌트킷(ComponentKit)이는 모바일 UI 프레임워크를 오픈소스로 내놨다. 현재까지 콤포넌트킷은 페이스북 기본 UI를 구축하는데 쓰인다. 뷰 제사용 풀, 뷰 평면화, 배경 레이아웃 계산 등으로 앱의 성능 향상에 기여했다. 또한 안드로이드 앱의 Litho와 스위프트UI에 영향을 줬다.

페이스북은 이후에도 애플 API와 자체 인프라를 혼용했다. 메타 신입 엔지니어는 애플과 내부 인프라를 함께 익혔다.

■ 2015년, 앱 시작시간이 길어지다

메타는 2015년 모바일 퍼스트 체제를 두 배로 강화했고, FBiOS 코드베이스의 일일 기여자수는 급격히 증가했다. 더 많은 제품이 앱에 통합되면서 앱 시작시간이 느려졌다. 시작시간이 30초까지 느려지며 OS에서 앱 작동을 꺼버리는 상황에 이르렀다.

성능 저하 요인은 다양한 것으로 조사됐다. 앱의 대형화로 '프리메인' 시간이 무한대로 늘었고, 앱의 모듈 시스템이 각 제품에 모든 리소스에 대한 통제되지 않은 접근 권한을 부여했다. 이에 따라 각 제품이 시작 시 연산비용을 많이 소모하는 작업을 수행함으로써 제품의 초기 탐색이 성급해지면서 공유지의 비극 문제가 발생했다.

■ 2016년, 동적라이브러리 도입

시작시간 개선에 대해 애플 위키에 따르면, 앱의 기본 기능을 호출하기 전 여러 작업을 수행해야 한다. 앱 코드가 많을수록 시간이 더 오래 걸린다.

프리메인은 앱 시작시간 30초 중 일부만 차지했지만 FBiOS에 지속적으로 새 기능을 추가하게 될 것이므로 큰 우려사항이었다.

초기에 구축된 페이스북 동적라이브러리 구성

페이스북 엔지니어들은 앱 실행시간의 증가를 완화하기 위해 동적라이브러리(Dylibs)로 대량의 코드를 옮기기 시작했다. Dylib로 DBiOS는 앱 시작 시간의 무한 증가를 억제할 수 있었다. 대부분의 코드가 dylib에서 끝나므로 시작 성능을 빠르게 유지하고, 앱에 추가되거나 제거되는 기능의 변동에 영향을 받지 않는다.

dylib는 메타 내 제품 엔지니어의 코드 작성 방식에 변화를 촉발했다고 한다. 결과적으로 앱 설계 방식에 큰 변화를 주는 계기로 작용해 새로운 앱 아키텍처를 만들게 했다.

■ 2017년, 자체 빌드 시스템 도입

페이스북은 동적라이브러리 도입으로 주요 구성요소를 다시 생각해야 했다. 모듈 등록 시스템을 더 이상 런타임 기반으로 삼을 수 없었고, 엔지니어가 시작시간 중 코드 경로의 동적라이브러리 로드 트리거 여부를 알 수 있는 방법을 고안해야 했다.

여기서 메타의 오픈소스 빌드시스템인 '벅'이 선택됐다. 벅 내에서 앱, 동적라이브러리, 라이브러리 등의 각 타깃은 몇가지 일부 구성으로 선언된다. 각 타깃은 종속성, 컴파일러 플래그, 소스 등 빌드에 필요한 모든 정보를 나열하고, 벅 빌드 호출 후 모든 정보를 쿼리할 수 있는 그래프로 빌드한다.

이를 사용해 FBiOS는 빌드 중 앱의 클래스와 기능에 대한 전체보기를 생성하는 몇가지 쿼리를 생성하기 시작했다, 이 정보가 앱의 차세대 아키텍처의 구성요소다.

■ 2018년, 코드 생성과 새 플러그인 시스템

FBiOSRK 벅을 사용해 종속성 코드 정보를 쿼리하게 되면서 함수와 클래스의 동적라이브러리 매핑을 즉시 생성할 수 있게 됐다. 이 매핑을 입력으로 사용해 FBiOS는 호출 사이트에서 동적라이브러리 열거형을 추상화하는 코드를 생성했다.

코드가 로컬 입력을 기반으로 재생성됐기 때문에 체크인 항목이 없고, 병합 출돌이 없어졌다. 이는 개발 효율성 개선을 의미한다.

FBiOS는 벅 쿼리와 코드 생성을 결합해 새로운 플러그인 시스템의 기반으로 삼았다. 이는 런타임 기반 앱 모듈 시스템을 대체했다.

벅 기반 플러그인 시스템 아키텍처로 이전하면서 FBiOS는 다수의 런타임 오류를 빌드 시간 경고로 대체할 수 있었다. FBiOS 구축 후 벅은 앱의 모든 플러그인 위치를 표시하는 그래프를 생성할 수 있다. 플러그인 시스템은 엔지니어에게 빌드시간 에러를 표출할 수 있다. 이에 엔지니어는 FBiOS의 성공적 구축 후 누락된 기능, 앱 시작 중 dylibs 로드 또는 모듈 런타임 시스템의 불변성 등으로 실패하지 않는다고 확신하게 됐다.

플러그인 시스템 이전으로 앱의 안정성을 향상시키고, 엔지니어에게 더 빠르게 신호를 주며, 앱이 다른 모바일 앱과 코드를 공유하게 됐다. 역으로 비용을 발생시켰다고 한다.

플러그인 오류에 참고할 정보가 시중에 적고, 디버깅하기 혼란스러울 수 있었다. 코드 생성과 벅을 기반으로 하는 플러그인 시스템이 전통적인 iOS 개발과 거리가 있었다.

플러그인은 코드베이스에 대한 간접 계층을 도입한다. 대부분의 앱이 모든 기능을 포함한 레지스트리 파일을 갖고 있지만, 이런 파일은 FBiOS에서 생성돼 찾기 힘들 수 있었다.

■ 2020년, 스위프트 증가와 언어 가이드라인 구축

메타는 2020년에 이르러 애플 SDK의 변경에 따른 아키텍처 결정을 다시 고민해야 했다. 애플의 스위프트 전용 API 수가 늘어나고 있었고, 스위프트를 더 많이 사용하자는 목소리가 커졌다.

FBiOS의 추상화 구축 수단은 전통적으로 C++이었다. C++의 제로오버헤드 원칙 덕에 코드 크기를 절약할 수 있기 때문이었다. C++은 아직 스위프트와 상호운용되지 않고, 콤포넌트킷을 포함한 대부분의 API를 스위프트에서 사용하려면 코드 팽창을 유발했다.

페이스북 언어 아키텍처 가이드라인

메타는 이에 언어 전략을 새로 수립하기 시작했다. FBiOS팀은 애플 스위프트와 향후 스위프트 API를 자유롭게 사용할 수 있도록 제품 관련 API와 코드에 C++을 포함하면 안된다고 조언하기 시작했다. FBiOS는 지금도 플러그인을 사용해 C++ 구현을 추상화해 앱에 사용하지만, 대부분의 엔지니어에겐 보이지 않는다.

■ 2022년, 완료까지 1% 왔다

관련기사

작년까지 FBiOS 아키텍처는 콤포넌트킷과 그래프QL 같은 사내 추상화를 다수 도입했고, 동적라이브러리를 사용해 시작시간을 줄였으며, 벅 기반 플러그인 시스템을 도입해 추상화와 앱 간 공유를 간소화 했다. 언어 가이드라인이 도입됐고, 코드베이스를 그 언어 가이드라인에 맞춰 옮기기 시작했다.

샤히데푸르는 "페이스북, 메신저, 인스타그램, 왓츠앱 등에서 더 많은 경험이 공유되면서 FBiOS는 모든 최적화를 다시 검토해 플랫폼 정통에 더 가까이 다가갈 수 있는 곳을 확인하고 있다"며 "궁극적으로 코드를 공유하는 가장 쉬운 방법은 앱에서 무료로 제공하는 것을 사용하거나 거의 종속성 없고 모든 앱 간에 통합할 수 있는 것을 빌드하는 것임을 확인했다"고 밝혔다.