4 ポイント 投稿者 GN⁺ 2024-04-29 | 1件のコメント | WhatsAppで共有
  • ウェブ連載が終わった後も、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 コードでウェブサイトに変換する形だった
  • 目標は最初から実物の紙の本であり、ウェブに最後の章を公開したあと約1か月休息した
  • ほぼ4年間毎日書き続けていたためかなり疲弊しており、2020年初頭の状況も作業を続けにくい時期だった

Dart で作り直したビルドシステム

  • まず読者が GitHub issue で報告した誤字や誤りを修正した
  • その後、本全体の ビルドシステム を Dart で書き直した
    • 最初の本のビルドスクリプトは、章ごとの Markdown ファイルを HTML にレンダリングし、コード断片を差し込む単一の Python スクリプトだった
    • Crafting Interpreters では、2つの完全なインタプリタのコードを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」、つまりメインのテキストボックスに沿って続く1本の連続したテキストフローを作る
  • 本文とコードスニペットはメインフローに入るが、aside と location marker は横に逃がす必要があった
  • 前作では aside を手作業で切り出して新しいテキストボックスへ貼り付けていたが、今回の本はコードスニペットが 1,133個 あるため同じ方法は不可能だった
  • InDesign は JavaScript スクリプティングをサポートしているが、ドキュメントとデバッグ環境は非常に貧弱だった
    • デバッガなし
    • スタックトレースなし
    • 一般的な debug print なし
    • alert() しか使えず、呼び出すとスクリプトが止まる
  • JavaScript スクリプトは aside と location marker を見つけてメインテキストフローから取り出し、別のテキストボックスにした
  • 位置指定の自動化は最後まで完成しなかった
    • InDesign の anchor 機能と Object Style で配置しようとしたが、一部のケースで周囲のコードスニペットの枠線が消える問題が起きた
    • 最終的に一部の location tag は手動で位置調整する必要があった

編集とコピーエディット

  • 本文全体を最初から最後まで読み直す 編集パス を行った
  • 各章は執筆中にすでに3回の draft を経ていたが、本全体の流れを見るためにもう一度見直した
  • この作業には 5か月 かかり、繰り返しになっていたジョークの大半を修正した
  • その後、プロのコピーエディタ Kari Somerton を雇った
  • 一般的な編集ワークフローでは Microsoft Word と Track Changes が多いが、著者は plaintext と Git ベースのワークフローを維持したかった
  • Kari Somerton は Git とカスタムビルドシステムを習得したうえで本全体を確認し、何百もの誤りを見つけた
  • すでに4回の draft と、読者からの何百件もの issue があったにもかかわらず、プロのコピーエディタは多くの問題を発見した

640ページ組版の制約

  • 十分に推敲した後、InDesign で章ごとの組版を進めた
  • 章ごとの作業は次の流れで繰り返された
    • 新しい InDesign ファイルを作成
    • XML を書き出す
    • XML を InDesign に取り込む
    • JavaScript で aside と location marker を切り出す
    • サイドバー要素の anchor を設定する
    • ページ末尾の空白を調整する
  • 最初の5段階は章あたり約30分で処理できたが、最後の空白調整が最も難しかった
  • 書籍の組版にはさまざまな 縦方向の配置制約 がある
    • 挿絵はページの途中で分割できない
    • aside は1ページ内に収まるほうが理解しやすい
    • コードスニペットも可能なら改ページで分断しないほうがよい
    • 見出しだけがページ末に残る状況を避ける必要がある
    • widows and orphans も避けたい
  • InDesign はこうした状況でコンテンツを次のページへ押し出すが、その結果ページ下部に大きな白い余白が生じる
  • 挿絵とコードスニペットは互いに絡み合う bin-packing 問題のように振る舞い、そのため章全体の組版に 2か月 を要した
  • 余白を減らすため、コードスニペットを2つに分けたり、画像周辺の余白を調整したり、挿絵の高さを変えたりする必要があった

挿絵、索引、前後付け

  • 挿絵は印刷向きの白黒ペン画を選び、最初のスキャン時に 1200 DPI で取り込んだ
  • 高解像度ビットマップとして書き出すのは簡単だったが、ページレイアウトへ配置する作業は難しかった
  • 本文が「Figure 123 を参照」という形式ではなく、すぐ横の挿絵を直接指す文構造だったため、挿絵は近い位置に置く必要があった
  • プロの索引作成者を雇わず、自分で 2週間 かけて全章を見直しながら索引を作成した
  • InDesign の索引機能は、選択したテキストを索引項目にして全体の索引を生成できたが、項目追加そのものは反復的で退屈な作業だった
  • 本の後ろには索引が入り、前にはタイトルページ、著作権ページ、献辞、謝辞、InDesign が生成した目次が入った

表紙デザイン

  • 著者は技術書の表紙の芸術性は小説ほど重要ではないかもしれないと考えていたが、教授の立場で販売を強制できるわけではないため、表紙には多くの時間をかけた
  • 当初は自分で撮った写真を表紙に使うつもりだったが、適切な写真が見つからなかった
  • 最終的に、本の視覚言語である ペンとインクの挿絵 を使うことにした
  • コンパイル過程を説明する山の絵を、より大きく詳細に描き直し、タイトル文字も新たに手書き風で作成した
  • タイトルは Acumin Pro Extra Condensed を印刷して手でなぞり、不完全さのある雰囲気を出し、1950年代の謄写版スカウトマニュアルのようなカラーパレットを選んだ

校正刷りと PDF 変更検証

  • PDF を KDP にアップロードして校正刷りを注文し、1週間後に重い箱を受け取った
  • 実物の本を見て初めて、このプロジェクトの規模をデータファイルではなく物理的な物体として実感した
  • 組版工程には手作業が多かったため、校正刷りを直接読みながら誤りを探し、sticky note で印を付けた
  • InDesign ファイルは Git リポジトリに入れていたが、巨大で不透明なバイナリファイルのため、ソースコードのように diff を見ることはできなかった
  • InDesign は実際には変更がないように見えてもファイルを書き換えることがあり、何が変わったのか確認しづらかった
  • 著者は Dart script を書き、本の PDF の全ページを抽出して1枚の大きな PNG タイル画像にした
  • コミットごとに PDF を書き出してタイル画像を作り、Photoshop action で2つの画像の異なるピクセルに赤い枠を描いて、変更されたページを見つけた
  • この方法は細かな変更内容そのものを直接示してはくれなかったが、どのページを目視確認すべきかを教え、想定した変更だけが入っているか確認できるようにした

電子書籍と公開

  • 印刷版の校正修正が終わった後、Kindle と EPUB の電子書籍も制作した
  • 独自ビルドシステムを修正し、EPUB が要求する古い XHTML、メタデータ、manifest を出力できるようにした
  • いくつかのコマンドライン実行で Kindle と EPUB 電子書籍を作成し、複数のリーダーでテストしながら CSS を調整した
  • 最終ファイルを用意した後、本のウェブサイトの最初のページを購入先へつながるよう更新し、写真やレスポンシブレイアウトも整えた
  • ストアへのアップロード、サイト更新、メーリングリストへの案内まで終えて、ようやく本は「本当に」完成した状態になった

その後の計画

  • 最後の章を書き終えた後も、人々は次の仕事や次の本のテーマを尋ねてきた
  • 著者は6年間1つのプロジェクトに打ち込んだあと、しばらく新しい本を計画しないつもりだ
  • パンデミックの間に先送りにしたことも多く、当面は何をするか決めずに休む考えだ
  • 音楽制作、釣り、友人や家族と過ごすこと、roguelike プロジェクトに取り組むことなどの可能性に触れているが、何をするかはすぐには決めない
  • いつかまた大きなプロジェクトをやりたくなるかもしれないが、1つのプロジェクトに再び6年を費やしたいとは思わないと述べている

1件のコメント

 
GN⁺ 2024-04-29
Hacker Newsのコメント
  • このページには書籍の購入リンクと無料のオンライン版リンクの両方がある: https://craftinginterpreters.com/
    この本は間違いなく買う価値がある。Nystromが実物の本のデザインに注いだこだわりだけでも、紙の本が好きな人には十分だし、手描きのイラストと素晴らしい文章も加わって、技術書の99%より優れていると思う

  • これまで読んだ技術書の中でも指折りによかった。各章で段階的に発展していくコードがあり、最終的に動くプログラムが残る構成は驚くべき発想で、それを実際にやり遂げた著者には感嘆する
    以前に似たようなものを書いたことがあるので、ツリー走査インタプリタの部分はざっと読んだが、Cベースのバイトコードインタプリタを追いながら、はるかに多くを学べた

  • 最近の記事だと思って、第二版が出たのかと思った
    著者にお祝いを伝えたい。この本は言語分野の技術的な深さだけでなく、レイアウトやグラフィックの細かなディテールまで、読み続けたくなる素晴らしい資料だ。長く通用する本のように感じる

  • 2017年にCrafting Interpretersを追い始め、前半を進めながら、loxの実装をJavaではなくScalaで書いたが、その過程でトークナイザー/レキサー/パーサー/インタプリタがまったく神秘的なものではなくなった
    以前は特定の種類のプログラマーだけが扱える秘伝の領域のように思っていたが、それはNystromの卓越した文章力と主題への深い理解のおかげだったと思う。2つ目のインタプリタはRustで書き始めたが、生活が忙しくなってあまり進められず、結局終わらなかった。そろそろまた戻る時期のようだ。この記事は数年前のものだが、紙の本として出ていたことは知らなかったし、自分の学び方には最適ではないとしても、手元に置いて著者を支援するために1冊買いたくなった

    • 自分も似たタイプかもしれない。Webベースの出版物の方が合っているが、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でレキサーを書き終えたところで、残りも楽しみだ。今のところ素晴らしい本だ