
Jachacks Winter에서의 경험
요약
Jac 프로그래밍 언어를 활용한 해커톤 참여 경험을 통해 Jac의 React Native 컴파일 지원 가능성을 탐색했습니다. React와 React Native의 내부 메커니즘 차이로 인해 발생하는 기술적 한계와 컴파일러 타겟 구현의 복잡성을 다룹니다.
핵심 포인트
- Jac 언어를 통한 React Native 앱 개발 및 정적 타입 검사 시도
- React와 React Native의 내부 엔진 및 렌더링 메커니즘 차이 분석
- 모바일 환경의 제한된 원시 요소로 인한 컴파일러 구현의 어려움
- React Native 지원을 위한 호환성 계층 또는 새로운 컴파일러 타겟 필요성
이 포스트는 Jac 프로그래밍 언어를 중심으로 진행된 해커톤인 JacHacks Winter에서 해킹(hacking)을 했던 저의 경험을 기록합니다.
저는 팀원 중 한 명(Chuka Ezeoke)과 제가 한 달 전 RocketHacks의 Jac 트랙에 참여하여 우승한 경험이 있었기에, 다른 사람들보다 Jac에 대해 더 많이 알고 있는 상태로 행사에 참여했습니다.
결국 저와 Chuka, Meron이 생각해낸 아이디어의 동기는 Jaseci 문서 사이트의 첫 번째 문장인 "무엇이든 만들기 위해 필요한 유일한 언어"에서 시작되었습니다. 그것은 매우 터무니없는 주장처럼 보였습니다. 실제로 그랬지만, 제가 발견했듯이 그 주장은 근거 없는 것이었습니다.
문서 어디에서도 모바일 개발(mobile development)에 대한 언급을 찾을 수 없었지만, 모바일 앱을 만들기 쉽게 만드는 것이 이 언어의 정신에 부합하는 것처럼 보였습니다. 결국, Jac는 웹 애플리케이션을 만들기 위한 언어 추상화(language abstractions)를 포함하고 있으며, 이는 상당히 참신하고 아마도 이 언어만의 독특한 점일 것입니다. 그렇다면 개발하기에 가장 수익성이 높은 플랫폼 중 하나를 포함하지 않을 이유가 있을까요? 컴파일러의 추가로 이제 React Native 앱은 실제 정적 타입 검사(static type checking)를 갖게 되었습니다 (Typescript 팬 여러분, 보고 계신가요).
당시 저의 작업은 모바일 개발에 크게 치중되어 있었기에, 저는 Jac의 React 내부 구조가 React Native의 컴파일 과정에도 깔끔하게 매핑될 것이라고 순진하게 가정했습니다. 결국 React Native는 React와 너무나 흡사해서 거의 그것과 다를 바 없어 보였으니까요! 하지만 제가 알아낸 바에 따르면, 실제로는 그렇지 않았습니다.
React Native가 단순히 HTML을 컴파일하여 모바일 뷰에 밀어 넣는 방식이 아니라는 점은 명확했지만, 내부 메커니즘의 상당 부분(솔직히 말해서 전부 다라고 해도 과언이 아닙니다)이 달랐습니다. 이것이 얼마나 다른지가 저에게는 놀라운 점이었습니다.
React는 JavaScript를 압축(minify)하여 단순한 HTML / CSS 웹 앱을 생성했습니다. 충분히 간단했습니다. 하지만 Android의 클래스 기반 Java SDK가 React의 원시 요소(primitives)를 따르는 것이 불가능했기 때문에, Facebook이 React Native의 내부 엔진을 구현한 방식은 Android의 네이티브 코드 위에서 실행되는 JS VM을 생성하는 것이었습니다. 이 방식은 UI 업데이트와 같은 생명주기 이벤트(lifecycle events)를 관리하는 데에만 React를 사용하고, 고도로 최적화된 Android 작업은 네이티브 C++ 코드에 맡겼습니다.
여러분이 질문하고 계신 것이 들리네요. 그럼 그 안에 React가 어딘가에 들어있다는 거죠? 그렇다면 React를 모바일로 트랜스파일(transpile)하는 것이 더 쉽지 않을까요?
꼭 그렇지는 않습니다. Android가 접근할 수 있는 원시 요소의 수가 (웹에서 사용할 수 있는 수십억 개의 HTML 태그와 대조적으로) 훨씬 적었기 때문에, React Native는 자체적인 UI 컴포넌트 라이브러리를 가지고 있었으며, 이와 더불어 해커톤의 22시간 동안 포팅하는 것을 불가능하게 만드는 수많은 미세한 특이점(quirks)들이 있었습니다.
따라서 React Native는 제가 다른 설정 플래그(configuration flag)를 통해 활성화할 수 있는 출력 형식(output format)이 아니었습니다. 이를 제대로 지원하려면 새로운 컴파일러 타겟(compiler target)이 필요하거나, Jac가 생성한 React 코드를 React Native 원시 요소로 변환하는 상당한 수준의 호환성 계층(compatibility layer)이 필요했을 것입니다.
우리가 사용할 수 있는 다른 기존 컴파일러 경계(compiler boundaries)가 무엇인지 살펴본 결과, 웹사이트를 네이티브 모바일 앱으로 변환할 수 있게 해주는 프레임워크인 Capacitor에 도달했습니다. 우리의 접근 방식은 Jac의 Vite 컴파일 경로를 가로채서(hijack) 최종적으로 모바일 앱을 렌더링하도록 하는 것이었습니다. 왜냐하면 두 방식 모두 번들링(bundling) 프로세스에 Vite를 사용했기 때문입니다.
아마도 제 능력에 대한 믿음이 부족했는지, Meron과 Chuka는 제가 나중에 Jac로 번역할 수 있도록 모바일 앱을 병행하여 개발하기 시작했습니다. 저희가 자체적인 요구 사항에 맞추기 위해 Jac 컴파일러를 제어하기 시작했기 때문에, 그들은 상당히 이례적인 일을 저질렀고 우리 프로젝트의 이름을 먼저 지어버렸습니다. 그것은 Hijac라고 불립니다 (이해하셨나요?). 이것은 휴대폰에서 실행되며 당신을 대신해 자율적으로 행동을 수행할 수 있는 모바일 에이전트 (mobile agent)가 될 예정이었습니다. 아래 차트는 왜 우리가 이 아이디어를 선택했는지를 보여줍니다.
예상대로 우리의 첫 번째 프로토타입 (prototype)은 세련되지 못했습니다. Vite는 React 출력물을 HTML과 CSS로 번들링 (bundle)했고, 순차적으로 Capacitor의 API를 실행하여 모바일 앱을 생성하는 cap sync를 호출했습니다. 또한 HMR (Hot Module Replacement)이 모든 수정 사항에 대해 완벽하게 새로고침되지 않았습니다. 하지만 중요한 부분은 작동했습니다. Jac로 작성된 애플리케이션이 설치 가능한 모바일 애플리케이션으로서 실행되고 있었던 것입니다.
이제 재미있는 부분인, 우리 에이전트를 위한 실행 계층 (execution layer)을 설계하고 앱이 마침내 무언가를 수행하도록 만드는 단계가 왔습니다. 다행스럽게도 Jac에는 또 다른 언어 기본 요소 (language primitive)인 OSP가 있었습니다. OSP는 그래프 (graph)를 일급 객체 (first class)로 만들었는데, 문서를 읽을 때는 이것의 용도를 잘 이해하지 못했지만 필요성이 나타나자 이해가 되었습니다.
에이전트 (Agents)는 사실상 루프 (loops)에 불과하며, 흥미로운 에이전트는 다양한 입력에 반응하여 여러 작업을 수행할 수 있는 것입니다. 그리고 멀리서 바라보면, 이것은 단지 하나의 그래프입니다. 그것이 구조화된 방식은 다음과 같습니다:
Node는 상태(휴대전화의 모션 이벤트와 같은)를 보유하며, walker는 해당 그래프를 가로지르고, 노드를 방문하며, 함수 호출 (function calls)을 수행하는 작은 자율 에이전트 (autonomous agents)입니다. 따라서 우리는 워크플로우 프레임워크 (workflow framework)를 구축할 필요가 없었습니다. 워크플로우는 단지 다음과 같았습니다: 센서가 작동하면, 이를 확인하기 위해 walker가 생성(spawn)되고, 해당 walker가 무엇을 할지(할 일이 있다면) 결정합니다. 사용자는 이 루프 (loop)를 지능적으로 구성하는 자연어 프롬프트 (natural-language prompt)를 통해 이러한 "워크플로우"를 생성할 수 있었습니다.
다음은 귀하의 휴대전화 모션 센서에 의해 실행된 walker입니다.
def infer_motion_decision(
snapshot: MotionSnapshot,
motion_threshold: float,
...
따라서 전체 에이전트 (agent)는 하나의 루프로 축소되었습니다:
낙상 감지 (fall detection)를 이용한 우리의 데모는 이 모든 것이 하나로 합쳐진 지점이었습니다. 만약 휴대전화가 떨어지면, 가속도계 (accelerometer)가 ~25 m/s²를 초과하여 급증한 뒤 몇 초간 정지합니다. 이때 walker가 생성되어 사용자가 넘어졌는지에 대한 신뢰 임계값 (confidence threshold)을 넘어서면, 자율적인 체인 (autonomous chain)을 시작합니다: 화면에 30초 카운트다운이 표시되고, 아무도 개입하지 않으면 비상 연락처로 실제 전화가 발송됩니다.
물론, 현대적인 휴대전화에 탑재된 수십 개의 센서를 사용하여 말 그대로 다른 무엇이든 할 수 있습니다. 예를 들어, 집에 가까워졌음을 감지하고 에이전트가 그날 당신에게 보상이 필요하다고 결정하면 피자를 주문하는 것과 같은 일 말입니다.
결국, 우리는 이 모든 것을 시연했고, 결과적으로 Social Good 트랙에서 1위를 차지했습니다.
다음은 작동 중인 에이전트의 영상입니다:
Hijac을 직접 사용해보고 싶다면, 코드는 Github에 있습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기
