4P by GN⁺ | ★ favorite | 댓글 1개
  • 웹 연재가 끝난 뒤에도 Crafting Interpreters는 실제 책이 되기까지 15개월의 추가 작업이 필요했고, 최종적으로 인쇄본·전자책·PDF로 완성됨
  • Markdown과 PNG 묶음을 책으로 바꾸려면 Dart 빌드 시스템, InDesign XML 가져오기, JavaScript 자동화, 조판 검증까지 새로 마련해야 했음
  • 최종 결과물은 8×10인치, 640페이지, 20만 단어 이상, 코드 스니펫 1,133개와 수백 개의 삽화를 담아 일반 웹 콘텐츠보다 훨씬 까다로운 레이아웃 제약을 가짐
  • 전체 재검토 5개월, 전문 카피에디팅, 2개월 조판, 2주 색인 작업, 교정쇄 확인과 PDF 비교 자동화가 이어짐
  • 자체 출판 기술서는 글쓰기만으로 끝나지 않으며, 빌드·레이아웃·검증·배포 자동화가 책의 품질과 완성도를 좌우함

웹 콘텐츠 완성 뒤에도 남은 작업

  • Crafting Interpreters의 본문은 이미 완성됐지만, 당시 결과물은 Markdown과 PNG 파일을 Python 코드로 웹사이트에 변환하는 형태였음
  • 목표는 처음부터 실제 종이책이었고, 웹에 마지막 장을 올린 뒤 약 한 달 동안 휴식함
  • 거의 4년 동안 매일 글을 쓴 뒤라 크게 지쳐 있었고, 2020년 초의 상황도 작업을 이어가기 어려운 시기였음

Dart로 다시 만든 빌드 시스템

  • 독자들이 GitHub 이슈로 신고한 오타와 오류를 먼저 고침
  • 이후 책의 전체 빌드 시스템을 Dart로 다시 작성함
    • 첫 책의 빌드 스크립트는 장별 Markdown 파일을 HTML로 렌더링하고 코드 조각을 끼워 넣는 단일 Python 스크립트였음
    • Crafting Interpreters는 두 개의 완전한 인터프리터 코드를 30장에 걸쳐 점진적으로 구성해야 해서 더 복잡한 빌드가 필요했음
  • 새 빌드 시스템은 특정 장이나 장 내부 특정 지점까지의 인터프리터 코드를 프로그램으로 출력하고, 이를 컴파일해 자동 테스트에 돌릴 수 있게 함
  • Python 기반 도구는 저자의 숙련도 기준에서 유지보수 부담이 컸고 속도도 느렸음
  • Dart 버전은 원하는 HTML과 구문 강조 코드를 정확히 생성했으며, 기존 Python 버전보다 10배 빠름
  • Markdown 처리 제어권이 커진 점은 이후 InDesign용 XML 내보내기에서도 유용했음

책 디자인과 판형 결정

  • 책 디자인은 웹 개발이나 게임 개발처럼 먼저 프레임워크를 만들고, 그 안에 콘텐츠를 붓는 작업에 가까웠음
  • InDesign에서는 페이지의 여백과 그리드를 정하는 master, 텍스트와 객체의 글꼴·스타일·색상을 정하는 style을 설정함
  • Crafting Interpreters는 디자인 난도가 높은 요소가 많았음
    • 본문 텍스트가 많음
    • 특정 문장, 코드, 삽화를 바로 옆에서 설명하는 긴 aside가 많음
    • 코드가 많고, 각 코드 스니펫 옆에 결과 프로그램에서의 위치 설명이 붙음
  • 가로 폭은 코드의 긴 줄, aside 영역, 두꺼운 책의 안쪽 여백을 함께 고려해야 했음
  • 저자의 책장에 있던 일반적인 CS 교재는 7.5인치 폭이 많았지만, 코드와 aside와 여백을 넣기 어려워 8인치 폭으로 결정함
  • 자가 출판에서는 KDP와 IngramSpark가 지원하는 제한된 판형을 써야 했고, 8인치 폭에서 합리적인 선택지는 8×10인치였음
  • 세로 방향은 고전적인 12pt baseline grid에 맞춰 텍스트를 정렬함

InDesign으로 옮기기 위한 XML 파이프라인

  • InDesign은 Markdown이나 저자의 빌드 시스템을 직접 이해하지 못해 수동 복사·붙여넣기는 현실적이지 않았음
  • InDesign은 XML 가져오기와 태그별 스타일 자동 적용을 지원함
  • 다만 XML 지원은 중첩 태그 처리에 제약이 있어, HTML처럼 헤더 안에 이탤릭 태그를 중첩하는 방식을 제대로 처리하지 못함
  • 저자는 빌드 시스템을 직접 제어할 수 있었기 때문에 InDesign이 받아들이기 쉬운 태그를 생성하는 custom XML exporter를 작성함

InDesign JavaScript 자동화와 한계

  • XML 가져오기는 InDesign의 “story”, 즉 메인 텍스트 박스를 따라 이어지는 하나의 연속 텍스트 흐름을 만들어줌
  • 본문과 코드 스니펫은 메인 흐름에 들어가지만, aside와 location marker는 옆으로 빼내야 했음
  • 이전 책에서는 aside를 수동으로 잘라내 새 텍스트 박스에 붙였지만, 이번 책은 코드 스니펫이 1,133개라 같은 방식이 불가능했음
  • InDesign은 JavaScript 스크립팅을 지원하지만 문서와 디버깅 환경이 매우 빈약했음
    • 디버거 없음
    • 스택 트레이스 없음
    • 일반적인 debug print 없음
    • alert()만 사용할 수 있고 호출 시 스크립트가 멈춤
  • JavaScript 스크립트는 aside와 location marker를 찾아 메인 텍스트 흐름에서 빼내고 별도 텍스트 박스로 만들었음
  • 위치 지정 자동화는 끝까지 완성하지 못함
    • InDesign의 anchor 기능과 Object Style로 배치하려 했으나, 일부 경우 주변 코드 스니펫의 테두리가 사라지는 문제가 생김
    • 결국 일부 location tag는 수동으로 위치를 잡아야 했음

편집과 카피에디팅

  • 본문 전체를 처음부터 끝까지 다시 읽는 편집 패스를 진행함
  • 각 장은 작성 중 이미 세 번의 draft를 거쳤지만, 전체 책의 흐름을 보기 위해 한 번 더 검토함
  • 이 작업에는 5개월이 걸렸고, 반복된 농담 대부분을 수정함
  • 이후 전문 카피에디터 Kari Somerton을 고용함
  • 일반적인 편집 워크플로는 Microsoft Word와 Track Changes가 많지만, 저자는 plaintext와 Git 기반 워크플로를 유지하고 싶어 했음
  • Kari Somerton은 Git과 맞춤 빌드 시스템을 익힌 뒤 책 전체를 검토했고, 수백 개의 오류를 찾아냄
  • 이미 네 번의 draft와 독자들의 수백 개 이슈가 있었음에도 전문 카피에디터가 많은 문제를 발견함

640페이지 조판의 제약

  • 단어를 충분히 다듬은 뒤 InDesign으로 장별 조판을 진행함
  • 장별 작업은 다음 흐름으로 반복됐음
    • 새 InDesign 파일 생성
    • XML 내보내기
    • XML을 InDesign으로 가져오기
    • JavaScript로 aside와 location marker를 빼내기
    • 사이드바 요소 anchor 설정
    • 페이지 끝의 공백 조정
  • 앞의 다섯 단계는 장당 약 30분이면 처리할 수 있었지만, 마지막 공백 조정이 가장 어려웠음
  • 책 조판에는 여러 수직 배치 제약이 있음
    • 삽화를 페이지 중간에서 자를 수 없음
    • aside는 한 페이지 안에 들어가는 편이 이해하기 쉬움
    • 코드 스니펫도 가능하면 페이지를 넘겨 쪼개지 않는 편이 좋음
    • 헤더만 페이지 끝에 남는 상황을 피해야 함
    • widows and orphans도 피하는 편이 좋음
  • InDesign은 이런 상황에서 콘텐츠를 뒤 페이지로 밀어내지만, 그러면 페이지 하단에 큰 흰 공간이 생김
  • 삽화와 코드 스니펫은 서로 얽힌 bin-packing 문제처럼 작동했고, 이 때문에 전체 장 조판에 2개월이 걸림
  • 공백을 줄이기 위해 코드 스니펫을 둘로 나누거나, 이미지 주변 여백을 조정하거나, 삽화 높이를 바꾸는 작업이 필요했음

삽화, 색인, 앞뒤 부속물

  • 삽화는 인쇄 친화적인 흑백 펜 그림으로 선택했고, 처음 스캔할 때 1200 DPI로 가져왔음
  • 고해상도 비트맵으로 내보내는 것은 쉬웠지만, 페이지 레이아웃에 배치하는 작업은 어려웠음
  • 본문이 “Figure 123 참고” 방식이 아니라 바로 옆의 삽화를 직접 가리키는 문장 구조였기 때문에, 삽화가 가까운 위치에 있어야 했음
  • 전문 색인 작성자를 고용하지 않고 직접 2주 동안 모든 장을 다시 훑으며 색인을 만들었음
  • InDesign의 색인 기능은 선택한 텍스트를 색인 항목으로 만들고 전체 색인을 생성할 수 있었지만, 항목 추가 자체는 반복적이고 지루한 작업이었음
  • 책 뒤에는 색인이 들어갔고, 앞에는 제목 페이지, 저작권 페이지, 헌정, 감사의 글, InDesign이 생성한 목차가 들어감

표지 디자인

  • 저자는 기술서 표지의 예술성이 소설만큼 중요하지 않을 수 있다고 봤지만, 교수 지위로 판매를 강제할 수 있는 상황이 아니어서 표지에 시간을 많이 들임
  • 처음에는 직접 찍은 사진을 표지에 쓰려 했지만, 적절한 사진을 찾지 못함
  • 최종적으로 책의 시각 언어인 펜과 잉크 삽화를 사용하기로 결정함
  • 컴파일 과정을 설명하는 산 그림을 더 크고 자세하게 다시 그렸고, 제목 글자도 새로 손글씨 느낌으로 만들었음
  • 제목은 Acumin Pro Extra Condensed를 출력해 손으로 따라 그려 불완전한 느낌을 줬고, 1950년대 등사판 스카우트 매뉴얼 같은 색상 팔레트를 골랐음

교정쇄와 PDF 변경 검증

  • PDF를 KDP에 업로드하고 교정쇄를 주문했으며, 일주일 뒤 무거운 박스를 받음
  • 실물 책을 보고 나서야 프로젝트의 규모를 데이터 파일이 아닌 물리적 물체로 체감함
  • 조판 과정에 수작업이 많았기 때문에 교정쇄를 직접 읽으며 오류를 찾고 sticky note로 표시함
  • InDesign 파일은 Git 저장소에 넣었지만, 거대한 불투명 바이너리 파일이라 소스 코드처럼 diff를 볼 수 없었음
  • InDesign은 실제 변경이 없어 보여도 파일을 바꾸는 경우가 있어, 어떤 변화가 생겼는지 확인하기 어려웠음
  • 저자는 Dart script를 작성해 책 PDF의 모든 페이지를 추출하고 하나의 큰 PNG 타일 이미지로 만들었음
  • 커밋마다 PDF를 내보내 타일 이미지를 만들고, Photoshop action으로 두 이미지의 다른 픽셀에 빨간 테두리를 그려 변경된 페이지를 찾음
  • 이 방식은 세부 변경 내용을 직접 알려주지는 않았지만, 어느 페이지를 시각적으로 점검해야 하는지 알려줬고 예상한 변경만 들어갔는지 확인할 수 있게 함

전자책과 출시

  • 인쇄판 교정 수정이 끝난 뒤 Kindle과 EPUB 전자책도 제작함
  • 자체 빌드 시스템을 수정해 EPUB이 요구하는 오래된 XHTML, 메타데이터, manifest를 내보낼 수 있게 함
  • 몇 가지 명령줄 실행 후 Kindle과 EPUB 전자책을 만들었고, 여러 리더에서 테스트하며 CSS를 조정함
  • 최종 파일을 준비한 뒤 책 웹사이트의 첫 페이지를 구매처로 연결하도록 업데이트하고, 사진과 반응형 레이아웃도 정리함
  • 스토어 업로드와 사이트 업데이트, 메일링 리스트 안내까지 끝난 뒤 책이 “정말로” 완성된 상태가 됨

이후 계획

  • 마지막 장을 끝낸 뒤에도 사람들은 다음 작업이나 다음 책의 주제를 물었음
  • 저자는 6년 동안 하나의 프로젝트에 매달린 뒤 당분간 새 책을 계획하지 않으려 함
  • 팬데믹 동안 미룬 일도 많았고, 당분간 무엇을 할지 정하지 않은 채 쉬려는 계획임
  • 음악 만들기, 낚시, 친구와 가족과 시간 보내기, roguelike 프로젝트 작업 같은 가능성을 언급하지만, 무엇을 할지는 즉시 결정하지 않음
  • 언젠가 다시 큰 프로젝트를 하고 싶어질 수는 있지만, 한 프로젝트에 다시 6년을 쓰고 싶지는 않다고 밝힘

댓글과 토론

Hacker News 의견들
  • 이 페이지에는 책 구매 링크와 무료 온라인 버전 링크가 모두 있음: https://craftinginterpreters.com/
    이 책은 확실히 구매할 가치가 있음. Nystrom이 실물 책 디자인에 들인 정성만으로도 인쇄물 좋아하는 사람에게는 충분하고, 손그림 삽화와 훌륭한 글이 더해져 기술서의 99%보다 낫다고 봄

  • 지금까지 읽은 기술서 중 손꼽히게 좋았음. 각 장마다 점진적으로 발전하는 코드와 실행 가능한 프로그램이 남는 구성은 놀라운 구상이고, 그걸 실제로 해낸 저자에게 감탄함
    이전에 비슷한 걸 작성해 본 적이 있어 트리 순회 인터프리터 부분은 훑어봤고, C 기반 바이트코드 인터프리터를 따라가며 훨씬 더 많이 배웠음

  • 글이 최근 것인 줄 알고 두 번째 출간이 나온 줄 알았음
    저자에게 축하를 전하고 싶음. 이 책은 언어 분야의 기술적 깊이뿐 아니라, 레이아웃과 그래픽의 작은 디테일까지 독서를 계속 붙잡아 두는 훌륭한 자료임. 오래도록 유효할 책처럼 느껴짐

  • 2017년에 Crafting Interpreters를 따라가기 시작했고, 책의 전반부를 진행하면서 lox 구현을 Java 대신 Scala로 작성했는데, 그 과정에서 토크나이저/어휘 분석기/파서/인터프리터가 완전히 신비롭지 않게 됐음
    예전에는 특정 부류의 프로그래머만 다룰 수 있는 비전 같은 영역이라고 생각했는데, Nystrom의 뛰어난 글쓰기와 주제에 대한 깊은 이해 덕분이었다고 봄. 두 번째 인터프리터는 Rust로 쓰기 시작했지만 생활이 바빠져 많이 진행하지 못했고 끝내지도 못했음. 이제 다시 돌아갈 때가 된 것 같음. 이 글은 몇 년 전 글이지만, 실물 책으로 냈다는 건 몰랐고, 내가 배우는 방식에는 최적은 아니지만 소장하고 저자를 지원하려고 한 권 사고 싶어짐

    • 나도 비슷한 편일 수 있음. 웹 기반 출판물이 더 잘 맞지만, Bob을 지원하려고 책도 샀음
  • 지금까지 읽은 컴퓨터 기술서 중 최고 수준이었음. 정말 아주 즐겁게 읽었고 많은 걸 배웠음
    훌륭한 기술 내용뿐 아니라 글도 잘 쓰였고, 재미있고, 삽화도 좋음. 기념비적인 성취라고 봄

  • 이 책에 대해 Bob이 이야기한 훌륭한 인터뷰라 들어볼 만함: https://corecursive.com/032-bob-nystrom-on-building-an-inter...

  • 아이러니하게도 책을 다 읽고 끝내는 데 15개월이 걸렸음 :). 저자의 상황에 크게 공감함. 성실하고 뛰어난 저자가 쓴 훌륭한 책이고, 책에 애착이 커져서 배운 내용을 바탕으로 페이지까지 만들었음: https://hexmos.com/compiler

  • 저자가 그래픽 디자이너에서 컴파일러 엔지니어가 된 건가? 놀랍고 인상적임

    • 책의 인쇄용 PDF를 만드는 데는 LaTeX보다 InDesign이 훨씬 빠를 것 같음. 나도 InDesign을 골랐을 것임. 나 역시 전직 디자이너임
  • 이 책이 책장에 꽂혀 있음. “Writing an interpreter in Go” 다음으로 읽을 인터프리터 책이 될 예정이고, 그 책은 약 200쪽이라 정말 마음에 듦

  • Java 대신 Rust로 어휘 분석기를 막 끝냈고, 나머지도 기대됨. 지금까지는 훌륭한 책임