Expo 공동 창립자 Charlie Cheever가 11월 9일 Exact 프리뷰를 공개하고 MIT 라이선스로 저장소를 오픈했습니다.
요약
Expo 공동 창립자 Charlie Cheever가 크로스 플랫폼 네이티브 앱 프레임워크인 Exact를 공개했습니다. 이 프레임워크는 단일 인터페이스 코드로 웹, macOS, iOS 등 다양한 환경을 지원하며, 에이전트가 애플리케이션 구축과 테스트 과정을 자동화합니다. 핵심은 자체 DSL(Contract)로 인터페이스와 상태를 정의하고 CSS 규칙을 계승하는 개발 방식입니다.
핵심 포인트
- 단일 코드베이스로 웹, macOS, iOS 등 다양한 플랫폼 지원 가능
- 인터페이스는 Contract라는 자체 DSL로 선언적(declarative)하게 정의
- 에이전트가 애플리케이션 구축 및 테스트를 자율적으로 수행함
- 스타일링은 CSS 규칙을 계승하며, 각 플랫폼의 네이티브 컨트롤 사용
- Contract 수정 시 페이지 재구축 시간이 99ms로 매우 빠름
Expo의 공동 창립자인 Charlie Cheever는 11월 9일에 Exact의 프리뷰 버전을 공개했으며, 해당 저장소는 MIT 프로토콜로 오픈 소스되었습니다.
I. 포지셔닝: 에이전트가 스스로 검수하는 크로스 플랫폼 네이티브 애플리케이션 프레임워크
Exact를 사용하면 동일한 인터페이스 코드를 한 번만 작성하여 웹(web), macOS, iOS, Linux 등 다양한 환경에서 컴파일 후 실행할 수 있습니다. 이 중 macOS와 iOS는 시스템의 네이티브 컨트롤을 사용하여 렌더링하며, Linux는 프레임워크 자체적으로 그립니다.
에이전트는 이 프레임워크 내에서 애플리케이션을 구축하고, 실행하고, 화면을 보고, 버튼을 누르고, 테스트를 수행할 수 있습니다. 이 모든 과정은 사람이 옆에서 지켜볼 필요가 없습니다. 이는 Exact가 대부분의 코드가 에이전트에 의해 작성된다고 가정하기 때문입니다.
현재 프로젝트는 pre-1.0 단계에 있으며, 반복 속도가 빠르지만 API 안정성을 보장하지 않습니다.
II. 개발 사고방식: 인터페이스는 독립적인 DSL로 정의하고, 스타일은 CSS를 계승하며, 오류는 컴파일 단계에서 차단
-
인터페이스 작성 방법
Exact의 핵심은 자체적으로 설계된 DSL(Domain Specific Language)인 Contract입니다. 이 DSL이 인터페이스를 정의하며, 데이터 로직은 TypeScript나 Rust 같은 다른 언어를 사용해 처리합니다.
DSL이란 특정 목적을 위해 설계된 언어로, 오직 인터페이스, 상태, 동작을 설명하는 역할만 하며 데이터를 계산하지는 않습니다.인터페이스, 상태, 동작은 app.contract 파일에 작성됩니다. 상태가 인터페이스의 모양을 결정하고, 동작이 상태를 변경하는 역할을 합니다. 데이터 측면에서는 DSL로 선언된 인터페이스에 따라 구현되며, 오직 데이터를 반환하는 역할만 수행하며, 매번 반환되는 필드는 사전에 선언된 필드와 일치해야 합니다.
작성 방식은 선언적(declarative)입니다. 모든 리스트에는 key가 있어야 하고, 모든 값에는 타입이 지정되어야 합니다. 동작이 어떤 상태를 변경할 수 있는지는 컴파일러가 호출 체인(call chain)을 통해 추론하며, 잘못 작성된 부분은 컴파일 단계에서 거부됩니다. 또한, 컴파일러는 무엇을 작성해야 하는지 알려줍니다. 시스템 시계 읽기나 난수 생성처럼 타입 검사로는 알 수 없는 경우도 있으며, 이런 경우는 실행 시점에 거부되고 로그(logs)에 기록만 남습니다.
-
스타일 처리 방법
별도의 스타일 시스템을 구축하지 않고 CSS 규칙을 그대로 계승합니다.font-size,line-clamp등 이름은 그대로 사용하며, 레이아웃 계산도 CSS 규칙에 따릅니다.
차이점은 누가 실행하느냐입니다. 웹에서는 페이지 구성과 그리기(drawing)를 브라우저가 담당하고, Apple 플랫폼에서는 시스템이 지정되지 않은 부분을 처리합니다. 글자 크기는 시스템 기본값을 사용하며, iPhone의 경우 17pt, Mac의 경우 13pt를 사용하고, 버튼은 시스템 버튼을 따릅니다. 특히 iOS에서 한 페이지에서 다음 페이지로 이동할 때 돌아가는(return) 기능 역시 시스템이 제공합니다.
명시적으로 작성된 부분은 작성자 기준을 따르며, 작성되지 않은 부분은 각 플랫폼의 기본값으로 채워집니다. 따라서 네이티브 렌더링과 웹은 완전히 같지 않으므로, 차이가 발생하는 부분은 규격에 명시하고 이유를 설명해야 합니다. -
개발 주기
Exact new에서 새로운 애플리케이션을 생성한 후 Contract 파일을 한 줄 수정하고 저장하면 페이지가 즉시 재구축 및 새로고침됩니다. 프로젝트 측 테스트 결과, 99밀리초(ms)가 소요되었습니다. 첫 네이티브 빌드는 10분에서 15분이 걸리지만, 그 이후에는 1~2분만 소요됩니다.
III. 에이전트 개발: 인터페이스는 열 가지 동작으로 수렴하고, 시계는 에이전트가 제어
프로젝트 측은 한 번의 전체 테스트를 기록했습니다. 이전에 사용된 프롬프트(prompt)를 사용하여 완전히 새로운 에이전트가 처음부터 사용할 수 있는 할 일 목록 애플리케이션을 만들었고, 세 플랫폼 모두에서 테스트를 통과하는 데 총 약 57분이 걸렸습니다. 이 중 25분은 첫 macOS 및 iOS 빌드에 소요되었으며, 이때 캐시는 이미 준비된 상태였습니다.
에이전트가 사용할 수 있는 인터페이스는 총 열 가지 동작으로 제한됩니다: 인터페이스 트리 읽기(read interface tree), 스크린샷 찍기(screenshot), 클릭(click), 입력(input), 상태 읽기(read state), 레이아웃 읽기(read layout), 로그 읽기(read log), 시계 제어(control clock), 환경 설정 지정(set preference), 성능 읽기(read performance). 네 가지 플랫폼에서의 동작은 완전히 동일합니다.
이 숫자는 의도적으로 통제된 것입니다. 이 인터페이스의 전신들은 합리적인 요구사항이 생길 때마다 이름이 하나씩 추가되어 결국 80개까지 늘어났습니다.
clock은 시간을 담당합니다. 두 동작 사이에는 애플리케이션 내의 내용물은 전혀 변하지 않습니다. 애니메이션과 타이머는 에이전트가 시간을 진행시킬 때만 앞으로 나아갑니다. 예를 들어, clock +60000은 1분을 전진시키는 것을 의미합니다.
따라서 테스트에서는 애니메이션이 끝날 때까지 기다릴 필요가 없으며, 시간 순서의 떨림(temporal jitter)도 발생하지 않습니다.
테스트는 이러한 동작들로 스크립트화되며, 동일한 스크립트는 어떤 플랫폼에서도 원본 그대로 실행됩니다. 저장소의 예시 애플리케이션인 Caltrain은 웹에서 세 가지 테스트가 완료되는 데 약 2초가 걸렸습니다.
IV. 실행 아키텍처: 인터페이스를 Plan으로 컴파일하고, 각 플랫폼별로 계층적 실행 수행
-
컴파일
Contract 컴파일러는 인터페이스를 Plan이라는 파일로 컴파일합니다. 이 Plan은 표(table)와 바이트코드(bytecode)로 구성되어 있으며, 런타임이 따라가서 실행해야 하는 내용입니다.
빌드 시 상수 데이터는 이 Plan에 직접 계산되어 포함되므로, 첫 프레임을 위해 데이터를 기다릴 필요가 없습니다.프로젝트 측은 React와 비교하는 그룹을 제공했습니다. RealWorld 기준에서 런타임 코드는 26 KB인 반면, React는 81 KB입니다. 또한 이 버전은 React의 서버 사이드 렌더링(server-side rendering) 버전보다 약 300밀리초 더 빨리 사용 가능하며, 해당 버전은 이때가 되어서야 하이드레이션(hydration), 즉 정적 페이지에 상호작용 기능을 연결하는 작업을 완료합니다. 이 수치는 프로젝트 자체에서 나온 것이며 제3자의 재검증을 거치지 않았습니다.
-
실행 및 레이아웃
웹에서는 이 Plan이 JS 파일과 약 20 KB의 런타임으로 변환되어 실제 DOM(Document Object Model)을 직접 조작하며, 레이아웃은 브라우저가 담당합니다.
네이티브 환경에서는 Rust로 작성된 runner가 동일한 Plan을 실행합니다. 이 runner는 Plan에 따라 순차적으로 진행되는 프로그램입니다.
그 옆에는 Rust로 작성된 레이아웃 커널(layout kernel)이 있어 CSS 규칙에 따라 각 박스(box)의 크기와 위치를 계산하며, 수정된 Taffy 레이아웃 라이브러리를 사용합니다. -
렌더링 및 정렬
렌더링은 각 플랫폼에 맡깁니다. macOS와 iOS는 AppKit과 UIKit을 사용하여 시스템 컨트롤을 그리고, 텍스트 측정에는 CoreText(애플의 타이포그래피 엔진)를 사용합니다. Linux는 자체적으로 그리며, GPU는 vello를, CPU는 tiny-skia를 사용합니다.
인터페이스에는 웹뷰(webview)도 없고, JavaScript 브릿지도 없습니다.
네이티브 단의 레이아웃, Canvas 2D, SVG, 그라디언트(gradient), 애니메이션은 모두 Chrome의 출력에 맞춰 교정해야 하며, 피할 수 없는 차이는 규격으로 작성하고 이유를 설명해야 합니다.
TypeScript 데이터 코드는 빌드 시점에 Hermes 바이트코드로 컴파일되며, 첫 프레임 이후에 로드됩니다. 네트워크, 파일, SQLite, 키 접근 가능 여부는 grants가 제어하며, 이는 데이터 모듈에서 접근 가능한 리소스를 항목별로 나열합니다.
GPU나 Markdown 에디터 같은 기능은 선택 사항이며, 필요에 따라 로드됩니다.
- 제한 사항: 아직 완료되지 않은 부분
Windows의 컨트롤과 시스템 네이티브 동작의 일관성, 그리고 배포는 아직 완료되지 않았습니다. Android는 초기 단계이며, 배포나 스토어 패키징이 되어 있지 않습니다.
Linux에서는 읽기만 가능하고 편집은 불가능하며, 태국어, 라오스어, 크메르어, 미얀마어의 줄 바꿈(hyphenation) 기능도 없습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 X Claude/Anthropic의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기