JavaScript의 탄생과 죽음 (2014)
(destroyallsoftware.com)- 1995년부터 2035년까지의 JavaScript와 프로그래밍 역사를 SF / 코미디 / 진짜 진지한 이야기 식으로 발표한 강연
- 2013년까지는 실제 역사에 기반한 내용이지만, 그 이후는 asm.js를 출발점 삼아 미래를 그려본 예측으로 전환됨
- 그런데 12년이 지난 지금 보면 그 예측의 상당수가 WebAssembly, 커널 내 VM(eBPF), 브라우저 위에서 돌아가는 거대 애플리케이션 형태로 실제 현실이 되어버림
- JavaScript에 대해 찬성이나 반대 한쪽에 서지 않는 중립적 관점을 취해, 언어의 결함을 솔직하게 다루면서도 산업에 미친 최종 영향은 매우 긍정적으로 평가함
- "더 우아한 언어가 아니라 더 나쁘지만 유일한 선택지였기에 우리를 탈출하게 만들었고, 그 힘이 이식성·보편성의 승리로 이어졌다"는 것이 발표를 관통하는 핵심 논지
- 정작 제목의 절반인 "JavaScript의 죽음"은 빗나가, 지금 JS는 TypeScript를 업고 그 어느 때보다 건재함
- 그럼에도 결함투성이 언어가 프로그래밍 산업 전체에 남긴 긍정적 영향이라는 메시지는 여전히 유효함
JavaScript의 탄생과 죽음
- 1995년 단 10일 만에 설계된 언어가 수많은 결함을 안고도 세계에서 가장 많이 쓰이는 언어로 올라섰다가, asm.js를 거쳐 결국 사라지기까지를 1995~2035년의 가상 역사로 추적
- 무대 위 결함 사례부터 미래의 커널 구조까지, JavaScript 한 언어가 아니라 프로그래밍 전반의 진화로 서사가 확장됨
- 2013년 등장한 asm.js가 브라우저 안에서 네이티브에 가까운 속도를 내며, C로 작성된 거대 소프트웨어를 통째로 브라우저로 옮기는 출발점이 됨
- 커널 안에 VM을 내장한 가상의 시스템 METAL이 하드웨어 격리를 대체하면서, CPU 아키텍처 이식성 문제 자체가 소멸하는 미래를 그림
- 결함투성이였고 동시에 유일한 선택지였기에 탈출 욕구를 낳았고, 그 힘이 이식성·보편성의 승리로 이어졌다는 것이 발표 전체를 관통하는 핵심 메시지
발표 개요
- 발표자는 소프트웨어 개발 스크린캐스트 회사 Destroy All Software를 운영했던 Gary Bernhardt, 발표 제목은 "The Birth and Death of JavaScript"
- 1995년부터 2035년까지를 다루는 가상 미래 회고 형식, 2013년까지는 실제 역사이고 이후는 사변적 전개
- JavaScript의 결함을 솔직히 짚으면서도 산업에 남긴 최종 영향은 매우 긍정적으로 평가하는 중립적 시각
1995년 — 브라우저에 들어간 10일짜리 언어
- 당시 다수의 컴퓨터는 Windows 95 환경이었고, 같은 해 출시된 Netscape Navigator 2에 새 언어가 포함됨
- 이 언어는 10일 만에 설계되었으며, Rich Hickey가 Clojure 설계에 약 2년 반을 쓴 것과 대비됨
- 10일 설계의 결과로 드러난 결함들
- 정수 없이 IEEE 754 배정밀도 부동소수점 단일 숫자 타입만 존재
- 인자를 빠뜨리거나 너무 많이 넘겨도 오류 없이 잘못된 동작을 조용히 수행
- 진짜 해시맵 없이 객체 타입만 있고, 모든 키가 문자열로 변환됨 (빈 배열을 키로 쓰면 빈 문자열 키가 반환)
- 정수 문자열 배열에
parseInt를 map하면 엉뚱한 결과가 나오는 등 기이한 동작 다수
2008~2009년 — 진지하게 쓰이기 시작한 JavaScript와 Node
- 2008년 전까지 JavaScript는 웹사이트의 사소한 동작을 위해 조금 쓰는 언어에 가까웠고, 진지한 프로그래밍 언어로 받아들여지지 못함
- Doug Crockford의 "JavaScript: The Good Parts" 출간이 언어를 진지하게 보기 시작한 전환점, 실제로 동작하는 소프트웨어를 만들 수 있는 부분집합을 추려냄
- 2009년 등장한 Node는 비동기 I/O 라이브러리와 JS 가상 머신을 한 패키지로 묶은 것
- 클라이언트와 서버에서 같은 언어를 쓸 수 있다는 점이 가장 큰 매력
- 다만 깊게 중첩된 콜백을 조장하는 단점, "도구가 보이는 사용 방식이 곧 그 도구가 조장하는 방식"이라는 관점 제시
- "Node는 프로그래밍 커뮤니티의 종양"이라는 익명 인용처럼 평가가 극단적으로 갈림
- 이런 분열 속에서도 JavaScript는 세계에서 가장 많이 쓰이는 언어가 됨
2013년 — ASM.js와 네이티브에 가까운 컴파일
- asm.js는 네이티브 코드에 매우 가깝게 컴파일되도록 설계된 JavaScript의 부분집합
- 타입 표기(annotation) 방식
- 인자에
| 0(0과의 비트 OR)을 적용해 정수임을 표기, VM이 단일 정수 덧셈 명령으로 컴파일 가능 - 인자에 단항
+를 붙여 부동소수점임을 표기 - 직접 작성하긴 끔찍하지만, 컴퓨터는 이런 표기를 100% 정확히 처리
- 인자에
- 실증 데모
- C로 작성된 CPython 가상 머신 전체(컴파일러·런타임·GC 포함, 약 3MB ASM)를 브라우저에서 hello world 실행
- C 25만 줄 규모의 Unreal Engine 3를 Firefox 안에서 네이티브의 약 절반 속도로 구동, 이 이식 작업은 Epic과 Mozilla 협업으로 5일 만에 완료
- 가장 의미 있는 지점은 게임 구동 자체가 아니라, 네이티브 정수 명령을 통해 정수·bignum·진짜 해시맵을 다시 가질 수 있게 된 점
2010년대 후반 — 개발 도구가 브라우저 안으로 들어감
- ASM 주변 도구가 자리 잡는 데 몇 년이 걸렸고, 후기 2010년대에는 소프트웨어 개발 도구가 먼저 포팅되기 시작함
- Z shell은 Chrome 안에서 실행됐고, 브라우저 안의 셸에서 편집기를 실행하고 백그라운드로 보내는 등 전체 셸 기능을 사용할 수 있음
- C 컴파일러는 브라우저 안의 셸에서
hello.c를 ASM 형태의 실행 결과로 컴파일했고, 그 결과물은 예상대로hello world를 출력함 - 특정 타깃으로 컴파일하는 컴파일러가 있고 ASM이 JavaScript와 하위 호환되면, 무엇이든 브라우저에서 실행 가능해짐
전쟁기와 2025년 — 거대 애플리케이션의 이식과 중첩된 런타임
- 전쟁이 벌어진 5년 동안 큰 진전이 없었고, 2025년 무렵부터 거대 애플리케이션 포팅의 속도가 다시 빨라짐
- 2025년부터 두껍고 거대한 애플리케이션이 브라우저로 이식됨
- Windows판 GIMP가 Mac판 Chrome 안에서 구동됨
- GIMP는 Win32를 호출하지만 Win32가 비공개이므로, Win32 재구현체인 Wine을 사용
- Wine은 X Windows와 통신하려 하지만 브라우저에는 X Windows가 없어서 X Windows shim이 필요했고, 이 구성 요소들은 모두 C에서 ASM으로 컴파일됨
- Chrome 자체도 C로 작성되어 있어, GIMP를 품은 Chrome을 다시 Firefox 안에서 구동하는 구성도 컴파일러와 라이브러리 조합으로 가능해짐
- Mac 윈도우 시스템이 비공개라 Cocoa 재구현체 Cacao까지 동원, Chrome과 Cacao도 C에서 ASM으로 컴파일됨
- 이 방식은 수백 MB 규모의 ASM 코드를 만들고 빠르지도 않지만, 필요한 라이브러리를 갖추면 거대한 기존 소프트웨어도 브라우저 런타임 안에서 작동함
- 실용성과 별개로 "결국 전부 컴파일러일 뿐(it's just compilers)"이라는 점에서 동작 자체는 성립
컴퓨터 동작 원리 — 4가지 짧은 강의
- 가상 메모리: 각 프로세스가 자신만의 주소 공간을 가진 것처럼 보이게 하는 간접 계층, 모든 메모리 접근이 물리 주소로 매핑되는 테이블을 거침
- 보호 링(protection ring): 사용자 프로그램은 하드웨어·메모리 매핑을 건드릴 수 없는 ring 3, 커널은 모든 권한을 가진 ring 0에서 동작
- 함수 호출: 레지스터를 스택에 푸시한 뒤 대상 함수로 점프, 반환은 그 함수의 책임
- 시스템 콜: 커널 주소 공간으로 점프할 수 없으므로 인터럽트(전통적으로 x86의 0x80)를 발생, ring 0 전환과 가상 메모리 테이블 전환을 거쳐 핸들러로 진입
- 이 전환 과정 상당수는 정작 하려던 작업(예: 소켓 읽기)과 무관한 순수 오버헤드
METAL의 부상 : 커널 안의 ASM VM
- Microsoft 연구 논문 인용: 하드웨어 기반 격리가 최대 33% 의 성능 비용을 유발하고 구현을 복잡하게 만든다는 지적
- METAL은 Linux 커널의 상당 부분에 ASM VM과 DOM 구현을 직접 내장한 가상의 시스템
- 네이티브 코드를 실행하지 않으며, 네이티브 머신 코드를 만나면 ASM으로 트랜스파일 후 커널이 다시 JIT
- 브라우저 탭 간 격리를 CPU가 아닌 VM이 이미 제공한다는 점에 착안, 하드웨어 격리를 VM 격리로 대체
- 성능 산술
- VM 통과 손실은 약 20%, 하드웨어 격리 제거로 얻는 이득도 비슷한 수준
- 1.2 × 0.8 = 0.96, 즉 2010년 하드웨어·C 코드를 METAL로 돌리면 평균 약 4% 더 빠름
- Python·JavaScript 코드라면 하드웨어 격리 비용만 줄어 순수 이득
- 2014년 당시 받아들이기 어려웠던 이유: 저수준 격리 메커니즘에 대한 이해 부족, 그리고 JVM·CPython VM처럼 기존 VM이 대부분 고수준이었던 탓에 기대치가 형성되지 못함
이식성의 승리와 배포 방식의 변화
- METAL에서는 네이티브 코드가 없으므로 CPU 아키텍처 이식성 문제 자체가 소멸, 전체 프로그래머의 약 60%가 해당
- 다만 C 언어의 수백 가지 미정의 동작 같은 컴파일러 차원의 이식성 문제는 잔존
- 애플리케이션뿐 아니라 데이터베이스·큐 서버 등 모든 의존성의 소스와 ASM 컴파일 결과를 함께 버전 관리에 저장하는 흐름
- 모든 의존성이 버전 관리에 있으면 배포는 그냥 push하고 재시작 하는 일에 가까워짐
- 서버에 특정 Python egg나 C 컴파일러가 있어야 하는 식의 배포 문제가 줄어들고, JavaScript는 ASM을 통해 세계를 장악했지만 언어 자체는 새 개발에서 거의 쓰이지 않게 됨
2035년 관점: JavaScript는 졌고 프로그래밍은 이김
- 지난 1년간 JavaScript를 한 줄이라도 쓴 사람은 수백 명 중 다섯 명 남짓, 사실상 신규 개발에서는 죽은 언어가 됨
- 바이너리 개념은 완전히 사라지지는 않았지만, 네이티브 바이너리 중심 구조는 더 이상 오래 지속되기 어려운 상태
- 컴파일러, 링커, 심벌 스트리퍼, 디버거처럼 네이티브 코드나 오브젝트 파일을 다루던 오래된 C 인프라는 사실상 죽은 구조가 됨
- Metal은 웹이 컴퓨터를 장악했다는 뜻이 아니며, ASM과 DOM이 웹에서 왔더라도 커널 안에서는 프로그래밍 언어와 렌더링 기본 요소로 쓰임
- ASM과 DOM 모두 결함투성이지만, 15종의 경쟁 CPU 아키텍처나 Cocoa·Win32·GTK·Qt 등 난립하던 윈도잉 시스템보다는 훨씬 나음
- JavaScript는 개발 언어로서는 사실상 죽었지만, 프로그래밍 행위 자체는 이김. 이식성 문제와 낡은 컴파일 인프라에서 벗어난 것이 산업 전체에 막대한 이득이었음
- JavaScript는 나쁜 설계였고 브라우저 안의 유일한 선택지였기 때문에, 개발자들이 그 언어에서 벗어나려는 강한 압력을 받음
- 만약 1995년 브라우저 언어가 충분히 좋았다면 탈출 욕구가 생기지 않았을 것이고, 선택지가 여럿이었다면 그중 하나로 충분했을 것
- 오직 하나뿐인 나쁜 선택지였기에 모두가 벗어나려는 힘이 작동
댓글과 토론
Hacker News 의견들
-
2020~2025년에 전 지구적 재난이 올 거라고 정확히 예측하긴 했는데, 재난의 종류만 틀렸다는 게 좋음(?)
아주 JavaScript답다- 거의 NaN% 정확도였다고 볼 수 있음
-
이 사람이 우리에게 이 걸작을 남겼다는 얘기가 아직 없다니 놀랍다
안 봤다면 하던 걸 멈추고 보길 권함. 오늘 하루 최고의 5분이 보장됨
https://www.destroyallsoftware.com/talks/wat- 그의 발표는 전부 훌륭함
Boundaries는 소프트웨어 아키텍처에 관해 본 영상 중 가장 통찰력 있었고, 지금도 복잡한 애플리케이션을 설계할 때 그 교훈을 떠올림
상태가 여기저기 흩어진 명령형 논리에 익숙한 사람에게 함수형 프로그래머처럼 생각하는 법을 알려주는 좋은 입문 자료이기도 함
https://www.destroyallsoftware.com/talks/boundaries - 이 발표에는 몇 가지 오류가 있고, 내가 본 것 중 두 가지만 적어봄
Array(16)을 호출한 뒤 구분자가 16개 있다고 말하지만, 실제로는 15개뿐이라 Batman 농담이 조금 깨짐
또{}+[]를 쓰고 객체에 리스트를 더한다고 설명한 뒤[]+{}가[object Object]를 주는 것과 결과가 다르다고 조롱하지만, 실제로({}+[])라고 쓰면 역시[object Object]가 나옴
왜{}+[]가 다른지는 퍼즐로 남겨둠. 힌트:Gurer vf ab bowrpg gurer.
- 그의 발표는 전부 훌륭함
-
JavaScript는 실제로 컴파일 대상이 되었고, 당시 영상에서는 asm.js였지만 지금은 WebAssembly가 나왔음
실제로 구현되고 네이티브에 가깝게 실행되는 걸 보면 예측이 꽤 맞았다고 보임
나는 주로 TypeScript를 쓰고, Electron 덕분에 웹 기술이 데스크톱 앱으로 포장되면서 웹 문법이 일반 프로그램 안으로도 들어왔음
Electron이 무겁고 별로라는 말은 있지만, Mac·Windows·Linux를 한 번에 지원하는 가장 빠른 방법이기도 함
여기서 말하는 “죽음”은 JavaScript를 직접 쓰지 않게 되지만 어디에나 깔린 기반 계층이 되는 상태이고, 실제로 그렇게 됐다고 봄- Flutter도 있고, 데스크톱 운영체제뿐 아니라 iOS와 Android도 지원함
개발 속도도 꽤 빠른 편이라고 봄
다만 Electron이나 네이티브 앱과 성능이 어떻게 비교되는지는 잘 모르겠음
작은 팀이라면 속도 최적화보다 실제로 출시하는 것에 맞추는 편이 훨씬 낫다 - JavaScript는 말하자면 새로운 어셈블리 계층임
컴파일러는 정의상 사람이 읽을 수 있는 코드를 기계어로 옮김
JavaScript의 장점은 Google이 V8으로 한계까지 밀어붙였고 NodeJS가 백엔드에서 매력적인 환경을 만든 뒤, PDF처럼 어디에나 있고 한 번 쓰면 어디서든 쓸 수 있다는 데 있음
WebAssembly보다 지금까지 우위를 가진 이유도 그 다재다능함이며, WebAssembly는 JavaScript만큼 널리 깔려 있지 않음
요즘 JavaScript는 사실상 TypeScript와 동의어가 됐고, 이건 엄청난 도약이었음. 여기서 숨은 영웅은 Angular 2였다고 봄
Angular는 처음부터 TypeScript를 택하면서 네이티브 JavaScript 버전도 제공했지만, 솔직히 그 버전은 거의 못 쓸 수준이었고 당시엔 강하게 비판받았음
흥미롭게도 기본 선택지로 TypeScript를 내세우지 않는 마지막 피난처가 React인데, NextJS 같은 주요 프로젝트들이 기본적으로 TypeScript에 의존하는 상황이라 ReactJS도 결국 무너질 것임
혁신이 다른 프로젝트에서 먼저 나오고 ReactJS가 따라가는 건 처음이 아니며, 여기서도 Angular가 앞서고 있다고 봄
JavaScript와 Python을 고르면 크게 틀릴 일은 드물다 - 그 “죽음”이 JavaScript가 직접 쓰이지 않는 기반 계층이 되는 뜻이라면, 내가 사는 시간선과는 다른 듯함
사람들은 여전히 엄청난 양의 JS를 직접 쓰고 있고, WebAssembly도 아직 웹 애플리케이션의 일반적인 실행 환경을 장악하지 못했음
WebAssembly 위에 무언가를 만드는 회사 사례는 찾을 수 있지만, Gary가 말한 종류의 대전환과 혼동하면 안 됨 - 영상 속 이야기에서는 JIT가 충분히 좋아져서 가상 메모리와 메모리 보호를 없앴음
그런 일은 전혀 일어나지 않았다 - 웹사이트로 충분한데 왜 앱을 만들어야 하나?
그걸 위해 웹 브라우저를 여러 개 실행할 필요는 없음
- Flutter도 있고, 데스크톱 운영체제뿐 아니라 iOS와 Android도 지원함
-
몇 년마다 더 나은 JavaScript를 발명하고, 다시 그걸 JavaScript로 트랜스파일함
- 대규모 채택은 언제나 좋은 설계를 이김
- 결국 다 어셈블리 코드임
JavaScript로 컴파일하는 것 자체에는 본질적으로 잘못된 게 없고, 고수준 언어는 순수 JavaScript가 직접 제공하지 않는 많은 보장을 구현할 수 있음
지금까지 써온 거의 모든 언어 보장은 원시 어셈블리에서는 깨질 수 있다
-
문제는 Wasm의 발전 속도가 여기서 예측한 만큼 빠르지 않다는 점임
DOM 조작이 없어서 여전히 JS를 접착 코드로 써야 하고, 아니면 HTML과 CSS를 아예 버리고 Flutter나 일부 Rust GUI처럼 모든 걸 캔버스에 렌더링해야 함
하지만 웹의 기능 집합을 잃는 건 아쉬운 일임- Flutter를 선택하는 사람들은 모든 브라우저에서 캔버스가 주는 일관성이, 제각각 구현된 웹 기능 집합을 얻는 것보다 더 가치 있다고 볼 것임
- DOM과 JS는 떼려야 뗄 수 없음
DOM API는 JS로 접근한다는 가정 아래 설계됐고, JS의 설계와 일부 “독특한” 특징도 DOM과 함께 쓰기 위해 만들어진 데서 부분적으로 비롯됨 - JS는 WASM보다 훨씬 접근하기 쉬움
즉석에서 디버깅할 수 있고, LLM에 넣어볼 수도 있으며, 래퍼도 없어서 만지고 실험하고 작업하기가 훨씬 쉽다
-
2014년에 Canadian Undergraduate Software Engineering Conference(CUSEC)에서 Gary Bernhardt가 이 발표를 라이브로 하던 걸 봤음
PNaCl은 바로 전년에 나왔고, Google은 Chrome과 ChromeOS 안에서 OpenSSH와 RDP 클라이언트를 교차 컴파일·실행·샌드박싱하는 데 쓰고 있었으며, Mozilla/Firefox 쪽은 그에 대한 대응으로 asm.js를 제안했음
당시에는 그냥 웃겼는데, 지금 보니 그 아이디어 중 꽤 많은 부분이 살아남았다는 게 놀랍다 -
Gary Bernhardt의 Wat 라이트닝 토크는 내가 가장 좋아하는 발표였음
이 글 제목의 발표보다 겨우 2년 앞선 것임
[1]: https://www.destroyallsoftware.com/talks/wat -
거의 모든 것이 각본대로 일어났음
이제 브라우저 기술에 완전히 기반한 또 다른 운영체제나 WASM OS를 기다리면 됨
webOS와 Firefox OS는 적어도 시대를 20년 앞서갔다- 전혀 아님
WASM은 그 명제를 확인해주는 게 아니라 반박함
그 명제는 JavaScript 호환 소스가 미래의 기반이 된다는 것이고, 일반 JavaScript가 형편없는 기반임에도 호환 하위 집합을 효율적으로 해석하도록 고도로 최적화된 JavaScript 엔진이 미래의 범용 플랫폼이 될 수 있다는 주장임
WASM은 저수준 대상이 되도록 설계된, JavaScript와 호환되지 않는 새로운 기반을 만들면서 이걸 근본적으로 거부함
WASM이 그 명제를 확인한다고 하는 건, 모두가 브라우저 안에 Rust 인터프리터를 갖는 미래가 그 명제를 확인한다고 말하는 것만큼 이상함
그렇게 주장한다면 결국 웹 브라우저가 어떤 언어로든 어떤 형태의 코드를 실행할 거라는 말일 뿐이고, 그건 이미 그러고 있음
영상은 명백히 “놀라운” 가능성을 다루는데, 문자 그대로 평소와 다름없는 모든 가능한 미래와도 일치한다고 보는 건 말이 안 됨 - ChromeOS를 언급하지 않은 기술적인 이유가 있나?
순수한 호기심에서 묻는 것임
그리고 내가 본 webOS 스크린샷들은 부활을 바라게 만들었음. 스마트 TV뿐 아니라 다른 곳에서도
- 전혀 아님
-
Bernhardt의 2035년 시간표에서 이미 절반을 지났음
JavaScript는 아직 죽지 않았지만, WebAssembly 안에서 자기 조사(弔辭)를 쓰고 있는 건 분명해 보임- 당신 가족의 여러 세대가 다 죽은 뒤에도 마지막 JS 명령은 아직 실행되고 있을 가능성이 큼
전 지구적 핵전쟁이 일어나지 않는 한, JS가 대부분의 인간보다 오래 살아남는 쪽에 걸겠음 - 매달 여러 고객사의 사이트를 검토하는데, 전부 어떤 형태로든 JavaScript를 쓰고 있음
PHP처럼 절대 죽지 않을 것임
- 당신 가족의 여러 세대가 다 죽은 뒤에도 마지막 JS 명령은 아직 실행되고 있을 가능성이 큼
-
JavaScript는 역대 최고의 프로그래밍 언어임