어디서 아플지를 고른다
derive 가족을 끝내고, 언어는 명백한 정리를 다 써 버렸다 —— 코어는 성숙했고, 이미 탐색한 도메인에서 앱을 늘려도 「문제없다」고 확인할 뿐, 어디가 나쁜지를 찾지 못하게 되었다. 그래서 다음 수는 feature를 짐작하는 게 아니라, 재는 것이었다: 언어에 정말로 없는 능력은 무엇인가. 답은 상상이 아니라 runtime을 grep해서 나왔다 —— 그리고 애매한 「dogfood를 더」를, 저마다 「세우면 하나의 빠진 힘을 존재로 강제하는」 네 도구의 정밀한 목록으로 바꿨다.
이 시점에 언어는 편안한 문제를 안고 있었다: 자기 테스트를 계속 통과하는 것이다. 셀프 호스트의 코어는 증명되었고, 도출된 거동은 완성되었고, 익숙한 도메인에서 세우는 새 앱 —— 또 하나 web 서비스, 또 하나 커맨드라인 filter —— 은, 어디가 나쁜지를 밝히는 게 아니라 언어가 문제없다고 확인할 뿐이었다. 그것은 편안한 곳이고, 머물기엔 위험한 곳이다, 왜냐하면 프로그램은 자기 자신의 형태가 닿는 아픔만 surface할 수 있고, 같은 나라의 네 프로그램은 이윽고 모두 문제없다고 합의하기에 —— 그것이 그래서가 아니라, 이미 하는 것의 너머에 결코 닿지 않기에. dogfood 방법은 프로젝트 전체의 엔진이었지만, 공회전하고 있었다.
방법을 자기 자신에게 향한다
고침은, 방법을 다른 물음에 향하는 것이었다. 「무엇을 세울까?」가 아니라 「어디서 세우는 것이 아플 까?」—— 왜냐하면 아픔이 signal이고, 목표는 그것을 기다리는 게 아니라 의도해 유발하는 것이었기에. 이 재구성은, 좋은 다음 프로젝트의 기준을 바꾼다. 좋은 것은 가장 유용한 도구를 낳는 게 아니라; 언어가 갖지 않은 능력에 곧장 걸어 들어가, 그것을 끝내는 데 그 능력을 기르기를 요하는 것이다. 도구는 미끼이고, 빠진 힘이 사냥감이다.
gap을 짐작이 아니라 잰다
핵심의 규율은, 그 gap들을 상상이 아니라 측정으로 찾는 것이었다. 앉아서 언어에 무엇이 빠졌는지 상상하기는 쉽고, 틀리기도 쉽다 —— 실은 없는 gap을 발명하거나, 있는 gap을 놓치거나. 그래서 상상이 아니라, runtime을 직접 심문했다: 다른 프로세스를 시작하는 수단을 grep —— 없음. raw한 단말 입력, 줄을 기다리지 않는 한 키 누름을 grep —— 없음. 전용 bytes 타입, 혹은 영이 박힌 문자열이 망가뜨리지 않는 바이너리 처리를 grep —— 없음, 바이트를 16진 텍스트로 부호화하는 workaround뿐. 이것들의 저마다가 가정이 아니라 실 코드에 대조되었고, 저마다가 실의, 확인된 부재로 돌아왔다. 아무것도 찾지 않는 grep은, 어떤 양의 추측보다 정직한 프런티어의 지도다.
애매한 계획이 정밀한 목록이 된다
그 측정에서 짧고 구체적인 목록이 떨어졌고, 각 항목은 그것이 강제하는 하나의 능력과 짝지어졌다. 빌드 도구나 태스크 러너는 다른 프로그램을 돌리는 힘 없이 존재할 수 없다 —— 그래서 프로세스 제어를 언어로 끌어들인다. 대화적인 단말 프로그램 —— 작은 게임, 텍스트 UI —— 은 raw한 키보드 입력 없이 존재할 수 없다, 그래서 단말 제어를 강제한다. 바이너리 형식의 parser —— 그리고 여기서 가장 날카로운 선택은 컴파일러 자신의 WebAssembly 출력으로, 언어가 스스로 emit하는 바로 그 바이너리를 읽게 된다 —— 는 정직한 바이너리 처리 없이 존재할 수 없다. 그리고 frontend bindings로 그려지고 구동되는 브라우저 게임은, 사람이 실제로 놀 수 있는 것을 겸하며 대화적인 web 입력을 행사한다. 네 도구, 네 힘, 한 줄 쓰기 전에 각 gap이 이름 지어졌다.
왜 「다르게 아프다」가 온 요점인가
넷을 꿰는 통일의 아이디어는, 각각이 서로와, 그리고 그 이전에 세운 모든 것과 다른 곳에서 아프도록 골라진 것이다. 이전의 애플리케이션은 모두 한 영역 —— 입력과 출력에 묶인 string과 record의 일 —— 에 살며, 그 아픔을 철저히 지도화했다. 이 넷은 의도해 그 영역을 떠났다: 하나는 프로세스 제어로, 하나는 raw 단말 I/O로, 하나는 바이트로, 하나는 브라우저로. 그것들을 펼치는 요점은 커버리지이고, 언어가 네 코드 생성 backend를 일치에 유지하는 것과 같은 정신이다. gap은 올바른 형태의 프로그램이 걸어 들어갔을 때에만 나타나므로, gap을 찾는 길은, 의도해 다른 형태의 프로그램을 의도해 다른 방향으로 보내는 것이다.
이 Part에서 이어지는 것은 그 네 도구, 하나씩, 그리고 각각이 존재로 강제한 힘이다. 아픔의 일부는 예측대로의 곳에 있었고; 일부는 아주 다른 곳에 있었다, 컴파일러에 오래 숨어 있던 몇몇 버그와, 언어로의 수정이 그것으로 쓰인 프로그램을 조용히 망가뜨린 하나의 자상을 포함해. 그 모두는, 여기서 이루어진 같은 결정에서 왔다: 언어가 문제없다고 확인하기를 그만두고, 어디가 문제인지를 찾으러 가는, 이라는.