TECH 으로 돌아가기
TECH HACKER NEWS 오늘 8분 읽기 29 READS

Gleam, 이제 얼랭 소스가 아닌 '추상 폼'으로 컴파일한다

Gleam, 이제 얼랭 소스가 아닌 '추상 폼'으로 컴파일한다
SOURCE IMAGE · HACKER NEWS

함수형 언어 Gleam이 v1.19.0을 공개하면서 컴파일 방식에 눈에 띄는 변화를 담았다. Gleam은 얼랭 가상머신(BEAM)과 자바스크립트 런타임을 모두 타깃으로 삼는 타입 안전 언어로, 그동안 BEAM용 코드를 생성할 때 얼랭 소스 코드를 뽑아낸 뒤 이를 다시 얼랭 컴파일러에 넘기는 방식을 썼다. 이번 릴리스에서 Giacomo Cavalieri가 얼랭 코드 생성기를 처음부터 다시 작성해, 소스 코드 대신 '얼랭 추상 폼(Erlang abstract forms)'을 산출하도록 바꿨다는 점이 핵심이다.

추상 폼은 얼랭 컴파일러가 내부적으로 사용하는 중간 표현으로, 얼랭 문법을 메타데이터가 달린 트리 형태로 나타낸 것이다. 원래는 얼랭의 토크나이저와 파서를 거쳐야 만들어지는 결과물인데, 얼랭 고유의 외부 텀 포맷(external term format)으로 바이너리 인코딩이 가능하다. Gleam은 이 바이너리를 그대로 적재함으로써 얼랭 컴파일러의 앞단, 즉 어휘 분석과 구문 분석 과정을 통째로 건너뛴다. 결과적으로 컴파일러 성능이 개선되어 얼랭에서 돌아가는 Gleam 프로젝트의 빌드 시간이 상당히 줄었다는 설명이다.

실무자에게 더 중요한 변화

빌드 속도보다 현장에서 체감이 큰 변화는 오히려 디버깅 품질 쪽이다. 과거에는 런타임이 참조하는 위치 메타데이터가 컴파일러가 만들어낸 얼랭 소스를 가리켰기 때문에, BEAM 크래시 리포트나 스택트레이스의 줄 번호가 실제 Gleam 원본과 어긋나는 경우가 있었다. 가장 가까운 함수 정도만 지목하는 수준이었다. 이제는 위치 정보가 원래 Gleam 소스에 정확히 대응하므로 스택트레이스의 줄 번호가 정밀하게 맞는다. 원문은 이 메타데이터가 edb 같은 디버거에서 Gleam을 완전히 지원하는 토대가 될 수 있다고 언급하면서도, 자신들이 그 작업을 직접 진행하지는 않았다고 분명히 선을 그었다. 운영 환경에서 장애 원인을 추적해야 하는 입장에서 보면 빌드 속도 향상 못지않게 의미 있는 대목이다.

성능 수치와 관련해 원문은 José Valim의 langcompilebench 프로젝트를 활용했다. 각각 100개의 함수가 'hello world' 문자열을 반환하는 모듈 100개를 컴파일하는 데 걸리는 시간을 재는 방식으로, v1.17.0과 v1.19.0을 비교했을 때 캐시 없는 전체 빌드 기준으로 상당한 개선이 나타났다고 한다. 다만 원문 스스로 이 벤치마크가 인위적이며 각 언어의 극히 일부 기능만 컴파일하는 한계가 있다는 점을 거듭 강조한다. 실제 프로젝트의 코드는 훨씬 다양하고 기능마다 컴파일 비용이 다르기 때문에, 이 수치만으로 언어 간 우열을 단정해서는 안 된다는 것이다. 참고로 Gleam의 컴파일은 증분(incremental) 방식이어서 일상적인 개발에서는 전체 재빌드보다 훨씬 빠르게 동작한다.

BEAM 바이트코드로 직행하지 않은 이유

자연스럽게 떠오르는 의문은 '왜 얼랭 컴파일러마저 건너뛰고 BEAM 바이트코드를 직접 생성하지 않느냐'이다. 원문은 그 편이 더 빠르고, Gleam의 타입 정보를 활용해 최적화된 코드를 만들 여지도 있다는 점을 인정하면서도 현실적으로 택하기 어렵다고 설명한다. 얼랭 소스나 추상 폼과 달리 BEAM 바이트코드는 고정된 규격이 아니라 가상머신 릴리스마다 진화하기 때문이다. 바이트코드를 직접 다루려면 얼랭 메인테이너와 긴밀히 협력하며 변경에 계속 발맞춰야 하고, 수십 년간 얼랭 컴파일러에 축적된 최적화를 다시 구현해야 하는 부담도 크다. 기업이나 학계의 지원 없이 후원으로 운영되는 커뮤니티 프로젝트인 Gleam으로서는 비용 대비 효과의 균형점이 추상 폼이라는 결론이다. 이미 Elixir도 같은 방식으로 얼랭에 컴파일된다는 점을 근거로 들었다.

자바스크립트와 주변 도구의 손질

자바스크립트 타깃도 개선됐다. Gleam의 case 표현식 기반 패턴 매칭은 중첩 if문으로 컴파일되는데, John Downey가 이를 더 평탄하게 생성하도록 고쳐 중첩 조건을 하나로 합치고 중간 변수를 줄였다. 흥미롭게도 압축·gzip 이후 번들 크기에는 거의 영향이 없지만, 자바스크립트 엔진이 최적화할 분기가 줄어든다. 또한 짧은 리스트 리터럴은 배열을 만들어 Gleam 리스트로 변환하던 기존 방식 대신 더 직접적인 코드를 생성하도록 바뀌어, 짧은 리스트를 많이 쓰는 Lustre 같은 라이브러리 기반 프로젝트에서 성능 이득이 크다. 긴 리스트에서는 이득이 없어 기존 배열 변환 방식이 유지된다. TypeScript 선언에서는 커스텀 타입의 변형(variant) 판별 함수가 타입 파라미터를 unknown으로 일반화해 정보가 소실되던 문제를, 오버로드를 추가해 가능한 한 타입을 보존하도록 바로잡았다.

빌드 도구 연동도 한 걸음 나아갔다. Elixir의 Mix, 얼랭의 rebar3에서 Gleam을 쓸 수 있도록 Rodrigo Álvarez가 컴파일러 기능을 노출하는 명령들을 손봤다. 이제 gleam이 BEAM 컴파일 시 필요한 .app 리소스 파일을 직접 생성하고, compile-package에는 src 디렉터리 코드만 적재하고 dev_dependencies를 건너뛰는 --no-dev 플래그가 추가됐다. 세 BEAM 언어는 런타임 상호운용 비용이 사실상 없지만 지금까지는 빌드 단계 연결이 까다로웠던 만큼, Mix에서의 Gleam 지원으로 이어질 토대라는 점에서 실용적이다.

이 외에도 언어 서버가 필드·인자 라벨에 대한 정의 이동, 참조 찾기, 이름 바꾸기를 지원하게 됐고(Alistair Smith), WebAssembly 빌드에는 브라우저에서 포매터를 돌리는 format_source 함수가 추가됐다(John Downey). 에러 메시지도 여러 기여자의 손을 거쳐, git 병합 충돌 마커나 레코드 업데이트 구문의 인자 순서 오류, Gleam에 없는 +=·*= 같은 연산자, 다른 언어에서 넘어온 잘못된 패턴 매칭 | 사용 등에 대해 맥락에 맞는 안내를 내놓도록 다듬어졌다. 화려한 신기능보다 컴파일 파이프라인의 토대와 개발 경험을 차분히 정비한 릴리스로 읽힌다.

SOURCE · HACKER NEWS
원문 전체 보기 → https://gleam.run/news/gleam-doesnt-compile-to-erlang-source...
SHARE
NEXT · CHOOSE

변화를 읽었다면,
내가 만들 수익 구조를 고릅니다.

정보를 더 모으는 데서 멈추지 않고, 광고·외주·판매·중개·구독 중 내 상황에 맞는 출발점을 정해보세요.

21가지 수익 구조 살펴보기 →
처리 중...