
안녕하세요오~~~😆😆 반갑습니다아~👏
지난 시간에는 새로운 아키텍처의 구성요소 중 하나인 Hermes를 배웠습니다. 오늘은 새로운 아키텍처의 다른 구성요소인, Turbo Module에 대해 알아보도록 하겠습니다!!! 짝짝짝짝~👏👏👏👏
앞에서 배운 JSI 파트 및 뉴아키텍쳐 미리보기 파트에서 Turbo Module이 언급되었으니 많은 관심 부탁드립니다!!
Turbo Module이 어떻게 도입 됐는지 이해하기 위해 기존 레거시 모듈의 한계에 대해 먼저 알아본 후, Turbo Module의 굉장하고 엄청난(?) 효과에 대해서도 알아보도록 하겠습니다! +_+
React Native를 사용해 본 경험이 있다면, JavaScript 코드와 플랫폼별 네이티브 코드가 React Native 브릿지를 통해 통신할 수 있도록 해주는 네이티브 모듈이라는 개념에 익숙할 것입니다. 이 브릿지는 JSON을 통해 플랫폼 간 직렬화를 처리합니다.
하지만 이 브릿지 기반 통신 방식은 New Architecture가 도입되면서 이제 레거시(Legacy Architecture) 로 분류됩니다. 흙🥲 흙🥲
이 방식의 구조적 한계에 대해 먼저 알아보고, New Architecture에서 새롭게 도입된 모듈 시스템인 Turbo Module에 대해 배워보도록 하겠습니다!
브릿지를 오가는 모든 데이터는 JSON 문자열로 직렬화·역직렬화를 거쳐야 하고, 모든 통신이 비동기 + 배치(batch) 로만 처리됩니다.
😎☝️: 여기서 배치방식이란, 호출을 모아서 한 번에 보내는 처리 방식을 말합니다.
JavaScript에서 네이티브 메서드를 호출할 때마다 매번 브릿지를 통하면 통과 비용이 크니까 요청들을 바로 보내지않고 메세지 큐에 담아둡니다. 그리고 다음 프레임에 이 큐에 담긴 요청들을 한꺼번에 네이티브로 넘깁니다.
JavaScript는 네이티브로 요청을 던진 뒤 결과를 기다리지 않고 바로 다음 줄로 넘어가고, 그 요청은 다음 프레임에 묶여 전달될 때까지 메시지 큐에서 대기합니다. 호출 시점엔 네이티브가 아직 요청 처리를 시작하지 않았으니, 동기적으로 결과를 받는 통신은 불가능한 구조입니다.
단순한 기능에서는 큰 문제가 아니지만, 주고받는 데이터가 커지고 호출이 빈번해질수록 이 직렬화 과정 자체가 병목이 되어 눈에 띄는 딜레이로 이어집니다.
게다가 JavaScript는 동적으로 실행되기 때문에 타입을 빌드 시점에 강제할 수 없습니다. 그래서 네이티브와의 브릿지 통신 시 런타임에 가서야 문제가 발생합니다. 또한, 앱 구동 시점에 모든 네이티브 모듈을 한꺼번에 로드해야 해서 초기 실행에도 부담을 줍니다.
그래서~ 요로한 문제들로 인해 React Native는 성능과 안정성 측면에서 한계를 안고 있었고, React Native 팀은 기존 네이티브 모듈을 대체할 새로운 모듈 방식으로 Turbo Module을 도입하게 됩니다. 🤩
앞서 살펴본 레거시 Native Module의 한계 중 비동기·배치 통신 문제를 극복하려면 새로운 방식이 필요합니다. New Architecture가 일관되게 지향하는 건 C++를 통한 직접·동기 통신이고, Turbo Module은 JSI를 기반으로 JavaScript와 Native가 직접 통신하는 차세대 네이티브 모듈입니다.
이전 포스팅에서도 강조했지만 New Architecture의 모든 구성 요소들은 유기적으로 연결이 되어있어 어떤 구성 요소든 단독으로 문제를 해결할 수 없습니다. Turbo Module 또한 홀로 성능을 끌어올릴 수 없으며, 앞서 살펴본 JSI와 Codegen으로 함께 성능을 풀어냅니다. ㅇ0ㅇ!!!!
Turbo Module은 첫 번째 한계였던 비동기·배치 통신 문제를 JSI의 직접 참조 방식으로 해결합니다. C++ 레이어인 JSI를 통해 JavaScript가 Native 객체를 직접 참조하면서, 데이터를 JSON으로 직렬화해 브릿지로 넘기던 과정 자체가 사라집니다. 직렬화 병목이 없어져 성능이 개선되고, 호출을 큐에 모아 보내던 배치 구조도 더 이상 필요하지 않습니다. 그 결과 Native의 결과를 즉시 받아오는 동기 호출이 가능해집니다.
두 번째 한계였던 타입 안정성 문제는 Turbo Module이 Codegen을 통해 해결합니다. 레거시에서는 JavaScript와 Native의 타입 계약이 어긋나도 모듈이 실제로 실행되는 런타임에 가서야 에러가 드러났습니다. Codegen은 TypeScript/Flow 스펙 하나로부터 양쪽 바인딩 코드를 빌드 시점에 함께 생성하기 때문에, 이런 타입 불일치를 모듈 실행 전에 빌드 단계에서 미리 잡아냅니다. 덕분에 Turbo Module은 런타임에야 드러나던 타입 불일치가 잡혀 런타임에 발생할 오류를 줄여줍니다. +_+!
😎☝️: 여기서 바인딩이란, Codegen이 생성하는 JavaScript와 Native를 연결해주는 인터페이스 코드를 말합니다.
세 번째 한계였던 초기 로딩 지연은 JSI 기반의 지연 로딩(lazy loading)을 통해 해결합니다. 앱 구동 시점에 모든 모듈을 한꺼번에 로드했던 레거시 방식과 달리, Turbo Module은 모듈이 실제로 호출되는 순간 처음 인스턴스화됩니다. 당장 쓰지 않는 모듈까지 시작 시점에 올릴 필요가 없으니, 모듈이 많아져도 초기 구동 부담이 줄어듭니다.
Turbo Module은 결국...
- JSI를 통해 동기 호출 및 지연 로딩을 보장하고,
- Codegen을 통해 타입 안정성을 확보합니다.
Wowowowow! 굉장하고 엄청나지 않나요~? 흐흐흐~
다음 포스팅에서는 새로운 아키텍처의 다른 구성 요소인 Fabric에 대해 알아보겠습니다!
(더 대단할지도~?🤔)
그럼 다음 포스팅에서 만나요~~ 😆👋
참조
https://github.com/reactwg/react-native-new-architecture/blob/main/docs/turbo-modules.md
면접 준비중에 많은 도움 되었습니다!! 감사합니다!