- 언어 런타임·JIT 같은 대안 구현은 성능이 좋아도 정본 구현의 변화와 사용자 기대를 계속 따라가야 해 채택이 제한될 수 있음
- PyPy, LuaJIT, TruffleRuby는 빠른 실행 성능을 보여줬지만 호환성 격차와 새 기능 추적 부담이 실제 배포의 장벽이 됨
- YJIT는 별도 Ruby 구현이 아니라 CRuby 내부에 들어가는 길을 택해 처음부터 CRuby 기능과 100% 호환되도록 만들었고, Shopify·Discourse·GitHub 등에 배포됨
- Crystal처럼 기존 언어와 매우 비슷하지만 호환되지는 않는 선택은 사용자가 “거의 Ruby지만 Ruby는 아닌” 차이를 계속 마주하게 만들 수 있음
- JSON 파서나 JavaScript처럼 공개 표준이 구현체와 분리된 영역에서는 대안 구현의 부담이 줄어들지만, 정본 구현이 사실상 표준인 생태계에서는 다른 전략이 필요함
반복되는 대안 구현의 함정
- 소프트웨어 세계에서는 기존 시스템의 더 나은 대안 구현으로 출발한 프로젝트가 정본 구현의 그늘에 갇히는 일이 반복됨
- 대안 구현은 기능, 성능, 생태계, 사용자 기대에서 표준처럼 받아들여지는 정본 구현(canonical implementation) 과 비교됨
- 정본 구현이 계속 변하면 대안 구현은 자기 방향을 정하기보다 그 변화를 따라가는 데 많은 에너지를 써야 함
- 전통적으로 인터프리터였던 언어에 JIT 구현을 붙이는 경우, 새 기능은 인터프리터에 더 빨리 들어가기 쉬워 JIT 쪽의 추적 부담이 커짐
PyPy, LuaJIT, TruffleRuby에서 보인 패턴
- PyPy는 Python용 고급 JIT 컴파일러로 CPython 대비 큰 속도 향상을 낼 수 있었지만, 실제 사용은 매우 적었음
- Python은 정기적으로 새 CPython 버전과 기능이 나오는 움직이는 목표물임
- PyPy는 이를 따라가는 데 어려움을 겪어 항상 Python 몇 버전 뒤처지는 상태가 됨
- Python 소프트웨어를 PyPy와 호환되게 만들려면 사용할 수 있는 Python 기능이 제한되고, 대부분의 Python 프로그래머는 이를 신경 쓰고 싶어 하지 않음
- LuaJIT는 기본 인터프리터 방식 Lua 구현보다 큰 성능 향상을 제공하며 높은 평가와 어느 정도의 실제 채택을 얻었음
- LuaJIT 제작자 Mike Pall은 많은 사람에게 뛰어난 프로그래머로 평가됨
- Lua 언어가 계속 새 기능을 추가하면서 LuaJIT도 여러 버전 뒤처져 있음
- 일부 Lua 사용자는 이 때문에 LuaJIT 사용을 꺼림
- Lua는 미니멀리즘으로 알려진 언어지만, 새 기능 추가를 늦추거나 Mike Pall과 조율하는 노력은 이뤄지지 않았음
- TruffleRuby는 Ruby JIT 중 가장 인상적인 성능 수치를 내세웠지만 배포는 제한적이었음
- 실용적 이유 중 하나는 TruffleRuby의 워밍업 시간이 CRuby보다 훨씬 길다는 점임
- CRuby가 기능을 계속 추가하면서 TruffleRuby 기여자들은 이를 따라가기 위해 노력해야 했음
- Ruby 사용자는 CRuby를 정본 구현으로 보고, 완전히 호환되지 않는 구현은 고려할 가치가 낮다고 봄
YJIT가 택한 다른 길
- YJIT는 또 하나의 Ruby JIT로 시작했지만, 별도 구현이 아니라 CRuby 자체 내부에 구축됨
- 이 선택은 여러 설계상 트레이드오프를 만들었지만, YJIT가 시작부터 모든 CRuby 기능과 100% 호환될 수 있게 했음
- 현재 YJIT는 Ruby의 “공식” JIT이며 Shopify, Discourse, GitHub 등에 배포되어 있음
- github.com이나 Shopify 스토어를 방문한 사용자는 YJIT와 상호작용한 셈임
- 지금까지 Ruby JIT 컴파일러 중 YJIT가 가장 큰 성공을 거뒀고, 그 성공에는 호환성이 핵심 역할을 했음
“이길 수 없으면 합류하라”만으로는 부족함
- 대안 구현으로 자신을 포지셔닝하면 정본 구현의 그림자 안에서 계속 따라잡기 게임을 하게 될 가능성이 큼
- 정본 프로젝트가 계속 진화하면 대안 구현은 자기 프로젝트의 방향에 대해 제한된 의사결정권만 가진 채 뒤따라가야 함
- 정본 구현에 합류하는 편이 더 나은 결과를 낼 수 있지만, 그것만으로 모든 경우가 해결되지는 않음
- Ruby 생태계의 Crystal은 Ruby와 비슷한 문법을 가진 정적 컴파일 언어이며 타입 추론을 사용함
- Crystal은 의도적으로 Ruby 호환을 목표로 하지 않고 Ruby에서 갈라져 나감
- Rubyist에게는 “거의 Ruby지만 완전히 Ruby는 아닌” 언어로 보이며, 실제로는 많은 미묘한 차이와 비호환성이 있음
- 이런 유사성은 사용자의 기대를 흔들고 혼란을 만듦
- Crystal은 처음부터 Ruby와 비슷하다고 마케팅하지 않았다면 더 나은 결과를 얻었을 수 있음
경쟁을 피하고 자기 방향을 갖는 선택
- Peter Thiel의 “competition is for losers”는 불필요하게 경쟁해야 하는 위치에 스스로 들어가지 말라는 맥락으로 사용됨
- 새 프로그래밍 언어를 만들려면 Python의 부분집합이나 기존 언어와 표면적으로 매우 가까운 무언가를 만들려 하지 않는 편이 낫다는 조언으로 이어짐
- 자기만의 것을 만들면 다른 구현의 성능, 기능 집합, 라이브러리 생태계를 맞춰야 한다는 기대에 묶이지 않고 자기 속도와 방향으로 시스템을 발전시킬 수 있음
- 이 조언은 언어나 시스템에 정본 구현이 존재하는 상황에 적용됨
- 공개 표준이 있는 영역은 예외가 될 수 있음
- JSON 파서는 비교적 작고 빠르게 변하지 않는 명확한 명세가 있어 자체 구현이 가능한 대상임
- JavaScript는 여러 브라우저 기반 구현이 존재하며, 이는 JS 명세를 관리하는 외부 표준 기구가 있기 때문에 가능함
- JS 표준 작업자들은 JIT 컴파일 구현이 성능에 중요하다는 점을 이해하고, 언어 진화를 그에 맞춰 이끎
- 이들은 가능한 한 빠르게 많은 새 기능을 추가하는 게임을 하고 있지 않음