2016/07/01

主観でプログラミング言語5種類をあっさり解説

現在プログラミング言語は200種類存在していると言われてるようですが、これはたぶんLisp族の言語だけを数えた値です。

あるプログラミング言語(汎用のもの)がどんな用途に適しているかは、人によって大きく意見が分かれるので、用途を絞ったからといって適したプログラミング言語が決められるわけではありません。そもそも今日の世界における用途が明日の世界にも存在するとは限らないし。

この記事では、ぼくがHello Worldくらいは書いたことがある言語5種類をあっさりと解説しようと思ったけど、そんな知識もないので、「プログラミングしてみたい人向け、言語に関する5つのアドバイス」です。学習しない言語の選択に役立ててください。

Go

それなりに具体的で明確な「Cを使う」理由があるのでない限り、Cで学べるようなプログラミングはGoで学んだほうがいいと思います。

HaskellかOCaml

これといった目的もなくプログラミングを始めたいなら、静的型付き言語で始めるほうがいろいろ実りがあると思います。異論は認めるけど。 HaskellやOCamlであれば、現代的なアプリケーションを試しに作ってみるのに必要なライブラリもそれなりに充実しています。

Scheme

Schemeがいいのは、コンピュータがなくてもプログラミングを学べる点です。Schemeの実装は黒板だと言われるくらいです。

正規表現

特定のアプリを意識した言語でプログラミングし始めるよりも、正規表現をひととおり自在に使えるほうが、最初のうちは役立つ場面が多いと思います。 Rubyとかも、最初は正規表現全開な感じでテキストフィルタを書いてみるのがいいと思います。

先生や友だちや同僚がよく知っている言語

というわけで、ぼくの近くにいる人はTeXから学ぶことになります。

2016/06/20

特殊エンジニア向け数学ガイドツアー本『グッド・マス』の話

6月25日、つまり今週末、『グッド・マス ギークのための数・論理・計算機科学』という本が発売されます。 話せば長い事情があって、発売前だけど訳者の次くらいに書籍の内容を熟知しているので、私的な紹介を書いてみました。

計算機のプロが書いた現代数学ガイドツアー

世に数学系の読み物はたくさん出版されています。純粋数学のプロが書いたものもあれば、そうでない人が書いたものもあります。 『グッド・マス』は、後者です。著者のマークさんは計算機科学のプロであり、数学のプロではありません。そのため、本書でいう「数学」も、コンピュータエンジニア的な目線で描かれます。 たとえば、連分数の話をするときはScalaで実装し始めるし、論理学の話をすれば「Prologはいいぞ」って始まるし、計算といったらチューリングマシンとBrainfuckでありλ計算です。 本書を一言で表すと、「コンピュータエンジニア、とくにプログラミング言語とか大好きっ子にとって興味深いであろう観光名所をめぐる現代数学ガイドツアー」です。 日常の言葉で抽象数学を分かりやすく伝える系の読み物を期待して読み始めると、肩透かしを食うと思います。

ちなみにですが、そういう方向で数学ネタを気軽に味わいたいとしたら、いまなら"Cakes, Custard and Category Theory"という本が面白いと思います。 『ケーキ、カスタード、それに圏論』というタイトルどおり、後半はまるまる圏論の何がおいしいのかを説明するのに割かれています。こないだ翻訳も出たようです(邦題には「圏論」ってないけど)。

この"Cakes, Custard and Category Theory"という本の著者であるEugenia Chengは、生粋のプロ数学者ですが、ユーチューバ―として有名だったりもします。

ナイフを振り回しながら教壇に立つチェン先生かわゆす。

『グッド・マス』の話だった

閑話休題。『グッド・マス』のゴールは、日常の言葉で抽象数学を語ることではなく、コンピュータ好きなら知っていて損のない数学ネタを一通りさらうことです。 とくに重視されてるのは、公理的に、論理を使って、構成的に数学という体系を捉える方法を伝えることです。 著者のマークさんは、冒頭の第1章から、数学の対象を日常的な感覚だけで語らないよう読者に促します。 エンジニアになじみのある日常的な感覚にも頼りつつ、数とか集合、証明といった対象を、現代数学というルールで捉えるやり方を正面から見せてくれる感じです。 数学の教科書とは違う方法で、コンピュータ好きな人が「生の数学」を味見する本だといえるでしょう。 これが本書の貴重なところだと思います。

もともと単発の記事をまとめた本ということもあって、あからさまなストーリーもなく、面白そうな部分だけをつまみ読みできます。「数って何?」みたいな前半の軽めの話題だけ読んでもいいし、Prologを使って一階の述語論理を学ぶ第4部だけ眺めてもいいし、公理的な集合論のノリをさらってみるだけでもいいでしょう。 特に最後の第6部は、正規表現とか再帰、λ計算、型といったプログラミング言語好き向けの話題で占められているので、この辺だけ読むのもお勧めです。 とはいえ後半は「数学をやってる現代人が暗に共有している意識を部外者が垣間見る」ことができるような構成になっているので、論理を扱っている第4部くらいからは順番に読むことをお勧めします。 自分は、はじめて原書を通しで読んだとき、第1章の自然数の説明でのっけからペアノの公理を持ち出してきたのも後半のためのネタ振りだったのかーと納得しました。

一方、『グッド・マス』にはあまり登場しない数学の話もたくさんあります。 解析とか位相に関するネタは本書にはまったく出てきません(ε-δのわかりやすい解説はないし、ドーナツとマグカップがどうこうみたいな話もない)。圏論もないです(Haskellのコードは出てきますが、正規表現の微分を実装するのに使われます)。 このへんの話題については期待しないでください。

あと、いわゆる一般人向け数学の本で必ず引き合いに出される黄金比については完全にコケにされているので、そういうのが好きな人は注意してください。 目次を見ると黄金比を扱っている章がありますが、これはマークさんが「おれは黄金比をもてはやす連中が嫌いだ」ということを表明するためにある章です。黄金比ネタが好きな人にはこの本はお勧めできません。

もうひとつ触れておきたいのは、なるべく読み手が飽きないようにしたいと思うあまりにマークさんの筆がちょくちょく滑るという点です。 ところどころ自由すぎる解釈で書き進めてしまった内容を、コンピュータ系技術書版元であるPragProgsには編集しきることができなかったのか、原書には突っ込みどころのある箇所や単純なミスがけっこう残っています。 ただし、そんな暴走気味の部分はcocoatomoが訳注などでしっかり引き締めてくれているし、 翻訳版のレビューをしてくれた方々(計算機と数学の両方に足をかけてるプロばかり)にも細かい部分まで目を通してもらえてるので、 原文の微妙な勘違いはかなり補正されていました。 翻訳版は、私が企画時にぼんやり思い描いていた以上に、かなり安心して楽しめる内容に仕上がっていると思います。

というわけで6月25日発売の『グッド・マス ギークのための数・論理・計算機科学』、コンピュータをふだんから使っていて、もうちょっと数学的な考え方を知りたいよという人には、とっかかりとしてお勧めです。

個人的なあとがき

本書のもとになっているのは、主に「数学」に関連したネタを扱う英語圏では有名な古参のブログ "Good Math / Bad Math" です。 "Good Math / Bad Math"は、いまほどインターネット上に一般向け数学ネタが溢れていなかったころから勢いのある筆致で数学系の記事を量産してきたブログで、 幾度かの移転を経て現在でもわりと活発に更新が続いています。

"Good Math / Bad Math"
http://www.goodmath.org

過去には『マンガでわかる統計学』の英語版に対する肯定的なレビューがアップされたことなんかもありました。 『マンガでわかる統計学』は英語版もかなりよく売れたんですが、その認知度はこのブログにおける紹介記事で一気にあがった感があります。 (ただしシリーズ全体の認知度として見ると、Boing Boingで『マンガでわかるデータベース』がネタ的に扱われたことのほうが大きい)

"BOOK REVIEW: THE MANGA GUIDE TO STATISTICS"
http://www.goodmath.org/blog/2008/12/13/book-review-the-manga-guide-to-statistics/

自分はたまたま『マンガでわかる統計学』の英語版に少し関与していたこともあって、 それからしばらく"Good Math / Bad Math"の記事をちょくちょくチェックしていました。 そんなある日、「このブログをもとにして本を出すよ」という記事が掲載されます。 しかも出版社はPragmatic Bookshelf社とのこと。 Pragmatic Bookshelf社といえば、『RailsによるアジャイルWebプログラミング』とか『プログラミングErlang』とか『情熱プログラマー』といったIT系書籍で有名な版元です。 これは面白い本になるに違いないと思いながら、続報を待つこと4年、ようやく2013年にベータ版の書籍が発売開始になったのでした。

さっそくβ版を自分で買ってKindleに突っ込み、一通り目を通してみて、「間違いなくそのうちどこかで日本語版が出るだろうな」と確信しました。 と同時に、あちこちマークアップの変換結果がコケていたりして、商品としての出来には微妙なところも感じていました。Pragmatic Bookshelf社では独自形式のXML原稿から紙の書籍と電子書籍を生成しているんですが、 それなりに数式が多く含まれる本書の原稿に対し、その変換処理の調整がいまいちうまくいっていないのは明白でした。

「どうせ日本語版が出るなら訳本には自分自身が関与したい、いやむしろ、自分が関与せずに日本語版が作られたら書籍として残念な出来になってしまいかねないぞ」 というわけのわからない使命感に駆られ、当時所属していた出版社で版権を抑えたうえで翻訳に興味がある有識者がいないかなーと思ってこんなツイートをしてみたのでした。

このツイートに見事に引っかかってくれたのが、そのちょっと前に「スタート代数」という勉強会を主催していたcocoatomoさんでした。 自分もスタート代数に何回か参加していたことから、お互いに何となく面識があったこともあって、企画を通して翻訳を進めてもらうまでは実に順調に話が進みました。 原著の原稿データから日本語版のPDFを自動生成する環境はこちらで用意し、cocoatomoさんにも翻訳をこまめにgit pushしてもらっていたので、 あとは日本語版が少しずつ形になっていくのを時々眺めていればいいという、(個人的には)きわめて理想的な感じで制作が進んでいきました。

ところが、翻訳がずいぶん進んで編集もぼちぼち開始し、これからいよいよ制作も本格化しようという段階になって、自分自身が会社を辞めるしかないという不測の事態になってしまいました。 発行までの実務は会社に残った同僚に引き継げることになったし、cocoatomoさんの好意でその後も翻訳制作の作業にリモートで口を出し続けることはできたのですが、直接の担当者として最後まで携われないまま辞めるというのは正直つらい選択でした(念のため補足しておくと、もっとつらいことがあったので辞めた)。

その翻訳版が、ついに6月25日に発行されることになりました。感無量です。 数式を含むマークアップの変換についても、仕込んでおいたCI上での作業プロセスを外注で回してもらえたので、書籍として申し分ない感じに仕上がっていると思います。いまの僕には、この本がものすごく売れても特に利益的なものはないのだけど(アマゾンアソシエイトについてはよろしくお願いします)、手に取ってもらう人が増えればとてもうれしいです。

2016/06/08

Markdown原稿をGitHubで管理して本にする仕組みが出版社で導入されないわけ

これ、FAQっぽいんで、ちょっと私見を書いておこうと思います。

とくに技術書に関しては、Markdownで原稿を書きたいとか、修正はPull Requestでもらえると楽とか、そういう便利な世界を知っている人たちが執筆者なので、 「MS Wordで書いてもらった原稿を、こちらでDTPの担当者に組版してもらいます。修正は紙に赤字か、PDFをメールで送るので、そこにコメントを入れてください」という古き良き時代の出版社のやり方を目にすると、 「出版社って遅れてるよなー」という感想を抱かれることが多いのだと思います。 その結果、「自分たちはITのプロとして出版のためのプラットフォームを作れるだろうから、それを使ってもらえないものか」という方向の考え方に至るのはよくわかります。

しかし、これには、二つの面から「ちょっと認識が違うから待って」と言いたい。

まず「認識が違う」と思うのは、プレインオールドでない方法も部分的にはすでにけっこう導入されているという事実です。 とくに自分は、全面的に「マークアップ原稿を最後の最後までGitHubで管理する」ための仕組みをもう何年も実際に運用して売り物の本を作ってきました。 なので、「出版の中の人は現代的なプラットフォームを使えない」と言われると、どうしても「ぼくはちがうもん」と言いたくなるんですが、なんで自分はできてるのか、という点についてはあとで改めて書きます。

もう一つ、「出版のための現代的なプラットフォームが必要」という話に対して「うーん」って感じてしまうのは、 ルールが決まってる組版で自由な表現をするための仕組みはどうするの?という点に対する回答がないことです。 これは、原稿の形式と版管理ではどうにもならない問題です。

実際にそういうプラットフォームで売り物の本を制作してきた経験からすると、毎回いちばん頭を悩ませるのは、 プラットフォームをチューニングして、「今回のプロジェクトで作りたい形の本を作れるようにする」部分です。 毎回同じ体裁で似たような本を作るなら、yamlなどの設定を書き換えることによるシステム的なチューニングだけで済むかもしれません。というか、実際に済んでいます。 それでも、そのチューニングができる人が出版社の中に必要になるんですが、その程度なら、まあ、システムのお守りをする人がプロジェクトごとに担当者に要件を聞いて調整すればいいでしょう。 頭が痛いのは、「この本では見出しでこんな表現をしたい」とか、「強調をいくつか使い分けたい」とか、「標準的ではない構成にしたい」とか、そういう個別の本の中身に対する要求に合わせたチューニングです。

そういう要求を吸収できるようにシステムを作りたいということであれば、Markdownの原稿では絶対に無理(無理)なので、素直にLaTeXでもなんでも既存のプラットフォームを使おうよ。。(本音)

勝手が許されない「組版」と、自由な「レイアウト」と、それを吸収するプラットフォーム

出版物は、特に紙の本は、歴史がそれなりにあるので細部のルール(いわゆる組版)がわりときっちりしてます。 そのルールを逸脱していると、単純に読みにくい本になります。 このへん、ブラウザのレンダリングに任せればいいという発想でWebページを作るのとは違っているので、 たとえソースがXMLベースの原稿でも、本気のページ組版のためには、通常のブラウザエンジンではなく専用のフォーマッターが使われています。 もしブラウザのレンダリングエンジンでJavaScriptとCSSを使ってきちんと組版しようと思ったら、専門の会社を一つ作らないといけないレベルで大仕事です。

そんなわけで、出版物というのは、組版というミクロな部分の見た目についてはあまり融通が利きません。 誰でも使えるInDesignというアプリケーションがあるのにDTPがプロの仕事として成立してるのは、 一昔前の業種がいつまでも生き残ってるのでも、デザインセンスが必要だからだけでもなく、組版という仕事が本質的に専門知識を要求されるものだからです。

そうはいっても自動組版したい人、軽量マークアップの原稿を機械的に組版したい人にとっての選択肢は、いまは主にバックグラウンドでLaTeXを使うプラットフォームになると思います。 で、そのLaTeXですが、ご存じのとおり鬼門ですよね。 もっとも、Markdown+PandocやSphinx、Re:VIEWでとりあえずページ組版されたものを出すなら既成のスタイルを使うだけなので、とくに苦労はいりません。

問題は、ちょっと違った見た目にしたり、新しいレイアウト要素を追加したかったりする場合です。 これにはLaTeXのコマンドを使って自分でスタイルを書くしかありません。 しかも、新しいレイアウト要素を追加するにはそれだけでは済まず、ソースにおける構造とレイアウトとのマッピングを定義する必要があります。 自分は、このような拡張が簡単にできないと死ぬと思ったので、かなり早い段階でそのためのDSLを開発してました。 これまで十年くらい、「マークアップしたテキスト原稿を版管理」しながら「本として最後まで作り込む」という環境を実現できてたのは、こういう仕組みを作ったからです。

なお、これは自分だけでなく、「マークアップしたテキスト原稿を版管理」しながら「成果物として最後まで作り込む」を実現している人は、だいたいこのような構造とレイアウトのマッピングをする仕組みを自分たちで作り上げてるようです、というのを昔開催した「版管理+自動組版」という勉強会で知りました。

厄介なのは、そういう仕組みを「誰もが使える」ようにする点です。 GitHubのようなベースとなるプラットフォームを使い始めてもらうためのハードルが高いわけではありません。 自分の経験だと、毎回の書籍原稿における文書の構造とレイアウトを実現するメカニズムの両方をそれなりに理解しないといけないのが唯一の障壁です。 そういうことを考えたい人が中に常駐していないと、プラットフォームがあったところで、多様な個々の本に対してそれを適用し続けることができないのです。

むしろ問われてるのは出版ビジネスの考え方かも

というわけで自分は、軽量マークアップのテキスト原稿をGitで管理して本にするという簡単な仕組みが出版社の中に普及しないのは、 そういうプラットフォームを使って勝手が許されない組版かつ自由なレイアウトを実現しながら本を作り込もうとする人が足りてないことが大きな理由だと思っています。

もっとも、これは「出版する本は作りこむべきだ」という個人的な思いによる分析なので、 単純なプラットフォームで実現できる形の本だけで出版というビジネスを回してやろう、という大胆な発想もありえると思います。 そういう発想を追求したい場合は、米O'reillyのAtlas+Safariのような仕組みや、Pragmatic Bookshelf社の取り組みについて調べてみるとよいと思います。

2016/05/14

TeXと10年戦ってわかったこと

世間では「TeX」と一口に言われているけど、実際には3つの異なる側面があります。10年以上TeXで何かやってきたわけだけど、「TeXはアレ」の本質はこの3つがごちゃごちゃになってるとこかなと思ったりしているので、書いてみました。

  • マークアップ形式としてのTeX
  • 組版エンジンとしてのTeX
  • プログラミング言語としてのTeX

TeXの話をするときって、これら3つが案外と区別されていないなあと感じることがあります。具体的には、組版エンジンとしての機能について言及している場面でマークアップ形式の話を持ち出されたり、マークアップの話をしているときに名前空間がないからダメといった感じでプログラミング言語として批判されたり、ようするに、あまり建設的ではない。

もちろん、TeXというエコシステムについて何か言うときにはこの3つが不可分で、それぞれを切り出して論じてもしょうがないんだけど、まあポエムなので気にしないことにします。

マークアップ形式としてのTeX

TeXのマークアップというと\{}がやたらに出てくるアレを思い浮かべると思いますが、「いわゆるTeXのマークアップ」と見なされているものに厳格な文法とかルールはありません。 よく、「XML自体はマークアップではなくマークアップを作る仕組みを提供するものだ」と言いますが、TeXはさらにひどくて、シンタックスさえもが自分の知っているTeXでない可能性があるのです。

現状のTeXは、いろいろな人や団体が過去に考案してきた「マークアップ」を、使う人が自分のユーザ文書の用途に応じて混ぜて使っている状態だといえます。 なので、たとえば「TeXのマークアップのパーザがほしい」といった要件を満たすものがあるとしたら、それはTeXそのものになります。 この、ユーザが目的に応じていくらでも変更できる余地がある、というのが、マークアップとしてのTeXの革新的かつ悲劇的な点なのかなと思っています。

とはいえ、だいたい用途ごとに「デファクト」のマークアップはあって、たとえば文章そのものに対する基本的なマークアップの文法でいま主に実用されているのはLamportさんが拡張したLaTeXです。 この、LaTeXで導入され、現在に至るまで主に使われている「いわゆるTeXのマークアップ」は、なかなかよく考えられているなあと思います(もとをただせばScribeのアイデアだし)。 数式に対するマークアップも、Knuthが考えたオリジナルTeXにおける数式の書き方を延々と使っているわけではなく、現在ではアメリカ数学会AMSが拡張したやつが広く使われています。 TeXの中で図を使うためのマークアップは、文章や数式とは別体系で、これはいまはTikZが主流になっています。

拡張したマークアップをパーズするための仕掛けはプログラミング言語としてのTeXで作ります。 また、その出力であるレイアウトは組版エンジンとしてのTeXで実現します。

というわけで、TeXのマークアップはひどい、ふつうの人には無理、という意見は、種々のマークアップが混在していることからくる感想なのかもしれないと思います。 \{}$はオリジナルのTeXに沿って使われることが大半なので、どれも構文は緩く似た感じになり、「えー、なんでこんな一貫性がないのー」って感じますよね。 できることに制約がないので、たとえば「○○用のマークアップとかないし、別の表現にするか」という発想にならず、「○○したいだけなのにこんな複雑なことをしなければならないのかくそが」という感想になりやすいという面もあると思います。

文章に対するマークアップとして見た場合、LaTeXのマークアップは別に筋は悪くはないんじゃないですかねえ。 現代的な構造化もできるし、もちろん必要に応じて拡張もできる(←そこがアレ)。 「マークアップ形式拡張のためのAPIを設計するセンス」を養う本とかどこかにないかなあ。

組版エンジンとしてのTeX

一部のアレな人以外、TeXを使う目的は組版でしょう。これについては、あまり批判的な人はいない気がします。 TeXは当初から組版のための要件がかなり高く、しかもそれが一通り実現されています。 さらに、それなりに長い歴史のなかで、本職の組版技術を知る人たちが自分たちの必要とする付加的な要件を本気で実現してきました。 そのため、ほとんどの人にとっては、世界中の多くの言語で実用的なブラックボックスとして機能できていると思います (ふだん使っているTeXが組版についてブラックボックスに見えない人は、マークアップとしての側面と混同しているか、ただの組版のプロでしょう)。

プログラミング言語としてのTeX

なんというか、KnuthはもともとTeXをプログラミング言語として設計するつもりはさらさらなかったんじゃないかなあと思います。 自分の秘書でも使えるようなマークアップを自分で後から定義できるだけの機能を詰め込んだら、必然的にチューリング完全になってしまったというか。 あるいは、組版エンジンとして必要だろうなーと思う機能を作りこんでいて、その機能を外部からつつけるようにしたら、必然的にチューリング完全になってしまったというか。 とにかく、プログラミング言語としてのTeXにまともな設計思想はない気がするし、プログラミング言語として使いやすくする開発とかもされてこなかった。 なので使いづらいのは当然だし、使いづらさを楽しむのもまた一興かもしれません。 そもそもこれだけの機能がなかったら、後に続く人たちが「自分たちも仕事で使える」ものに魔改造できなかっただろうし(←その結果がアレ)。

とはいえ、そうも言ってられないという人たちは一定数いて、その先鋒がLaTeX3プロジェクトです。 それこそもう10年以上の歴史があるけど、過去のTeX資産を壊さないように慎重に開発が進められているので、いつになってもLaTeX3は完成しません(←だからアレ)。

とはいえ、LaTeX3のうちプログラミング言語として利用できる部分については現在のLaTeX2eでも使える状態にあります(expl3という)。 使いやすいかどうかはともかく、名前空間が実現できたり、関数っぽいものが定義できたり、プログラミング言語としてはふつうになってると思います。 次の10年に期待ですね(それまで選択肢がTeXしかないのも微妙だけど)。

2016/05/02

執筆・編集のためのGit(GitHub)ワークフローを考えてみた

まとまった量の文章を執筆・編集するのにバージョン管理システムを使うことは、少なくとも技術文書においては特別なことではなくなりました。 原稿が汎用のテキストファイルの場合には、バージョン管理システムとして、GitやMercurialなどのソフトウェア開発用のツールを使いたいことが多いと思います。 実際、GitHubやGitBucketを利用して技術書やドキュメントの原稿を共同執筆するという話はとてもよく聞きます(知っている世間が狭いだけかもしれないけど)。

とはいえ文章の執筆・編集という作業には、プログラムのソースコードを開発する作業とは違う側面もいっぱいあります。 そのため、ツールとしてはソフトウェア開発用のバージョン管理システムを利用する場合であっても、そのワークフローについては、執筆・編集ならではの工夫が多少は必要なのかなと考えています。

もちろん、同じソフトウェア開発でもプロジェクトの種類や参加者の考え方によって最適なワークフローは異なるだろうし、 ソフトウェア開発で成功するワークフローが執筆・編集には適用できないなんていうことでもありませんが、 こうやったら技術書を作る時にうまくいった、あるいはうまくいかなかったという経験に基づく考察をここらでいったん公開しておくのは悪くないかなと思ったので、まとめてみました。

なお、あくまでも経験に基づいた独断を書きなぐったものなので、これが正解と主張するものではないし参考文献とかもありません。 また、バージョン管理システムとしてGit(GitHub)が前提の書きっぷりになると思いますが、これも自分の経験に基づく話だからというだけです。 が、だいたいどのバージョン管理システムでも通用する話であろうな、とは想像しています。

目次

  1. 正史モデル:伝統的な文章のバージョン管理ワークフロー
  2. 執筆・編集というプロジェクトの実態
  3. 「じっくり読まなければ何となくいい感じ」が分水嶺
  4. 執筆・編集にとって最適(いまのところ)だと思っているGitワークフロー
  5. 余談:「じっくり読まなければ何となくいい感じ」に到達したことを知るには

正史モデル:伝統的な文章のバージョン管理ワークフロー

旧来、印刷して出版される文書は、初校、再校、念校、下版といった形式でバージョン管理されていました。 複数の関係者がいる場合には著者の代表や編集者が全員の意見(赤字)をマージして一つの修正指示を練り上げ、それが次の校正に反映されるというワークフローです。 つまり、正史が一つだけ存在するモデルです。

この伝統的な正史モデルのワークフローに、バージョン管理システムを適用したいとして、いちばん分かりやすいのは次のようなマイルストーンの細分化でしょう。

従来であれば数日から数カ月おきに確定するバージョン(初校とか再校とか)の間に、バージョン管理システムを使って細かくコミットを重ねていくイメージです。 さらにこのワークフローを突き詰めれば、初校や再校といった従来のマイルストーンの役割も消えて、全期間にわたってコミット履歴だけが並ぶことになるでしょう。 もちろん何らかのマイルストーンは設定することになるでしょうが、いずれにせよワークフローとしてはあくまでも一直線です。

このワークフローでは、みんなが同一のmasterに対してコミットを重ねていくため、誰かの作業内容が妥当であるかどうかを意識的に確認する役割の人がいるのがベターです。 ただし経験では、そのような役割を特定に人に押し付けるのではなく、関係者全員が「あれっ」と思った時点で履歴を検索して適宜blameや再修正をかけられるような空気があるほうが、うまく回ることが多かったと思います。 そのような空気は、関係者どうしの広帯域なコミュニケーションを通じて醸成されますが、 メール(メーリングリスト)、バグトラッキングシステム(TracやGitHub issue)、会議システム(SlackやSkype)を複数併用していた場合にわりとうまくいっていた印象があります。

執筆・編集というプロジェクトの実態

正史モデルのワークフローには、従来型の延長なので比較的導入しやすいというメリットがありますが、制限もあります。 このワークフローでは、どのコミットも、それまでの作業を塗りつぶして上書きする作業として扱います。 あとからコミット単位でrevertしたりrebaseしたりすることをあまり考慮していないワークフローだということです。

せっかくバージョン管理システムを使うのだから、作業の内容を明確化してブランチを切ったり、 それをあとからチェリーピックしたりマージしたり、逆に過去に加えた変更をなかったことにしたり、 そういうことができるほうがうれしいですよね。 正史モデルに拘泥してアドホックな上書き修正を積み重ねるのではなく、修正の意図や作業内容に応じてコミットをきっちり切り分けることで、原稿の変更による手戻を防いだり差分を見やすくしたりできるはずです。

ところが、経験上、文章の執筆・編集では作業内容ごとにコミットを整理したりブランチを切ったりするのが難しいなあと感じる場面がとてもよくあります。 文章の修正を局所的で互いに独立したコミットに収めることができず、コミットどうしが密に結合したり、一見すると巨大すぎるような修正コミットが発生したり、他の人の作業と競合したりしがちなのです。

もちろん、だからといって文章の執筆・編集では正史モデルで徹頭徹尾やるべきという話ではありません。 これまでの経験で感じるのは、うまくコミットとして切り分けられる問題もあれば、コミットとして切り分けるのが徒労でしかないような問題もある、という単純な事実です。 この二種類の問題を整理したところ、執筆・編集という作業には2つのフェーズがあり、この両フェーズを意識するとそこそこ最適なワークフローが説明できそうだなと気がつきました。

執筆・編集には2つのフェーズがある

正史モデルの説明では、「脱稿」以降のワークフローについてバージョン管理システムを使うかのように説明しましたが、あれは嘘です。 バージョン管理システムを使って、共著者、編集者、外部のレビュアーによる共同作業を始めるのは、脱稿よりも前の段階、具体的には「内容をすべて書き出した」時点であるべきです。

ここが重要なんですが、「内容をすべて書き出した」時点は脱稿とは異なります。 「内容をすべて書き出した」時点は、ソフトウェア開発でいうと、まだ最低限の機能がコンパイルすら通っていない状態です。 ここから待っているのは下記のような作業です。

  • 段落や節の見直し、統廃合、順序の入れ替え
  • それにともなう文章の書き直し、表現や語調の調性
  • 全体にわたる用字用語(漢字の使い方とか)の統一、誤用や誤植の修正
  • タグやメタ情報(ルビとか索引とか)の修正、追加

各作業について具体的な内容には踏み込みませんが、ようするに、全体にわたる読み直しとリライトを何度か繰り返すことで、これらの問題をひとつずつ潰していく必要があります。 そうやって確認と修正を繰り返していると、あるときふいに原稿が「じっくり読まなければ何となくいい感じ」になっていることに気づきます。 このへんでようやく、ソフトウェアでいえば警告を無視すればコンパイルが通った状態、つまり本当の意味での「脱稿」の一歩手前です。

「じっくり読まなければ何となくいい感じ」が分水嶺

「じっくり読まなければ何となくいい感じ」ゾーンまでくると、文書の骨組みや各文に対する大幅な修正は起こりにくくなります。 したがって、「どこそこのタイポ修正」とか「この文を修辞的に書き換える」とか「この段落は内容が疑わしい」といった具合に、文書に存在する問題を局所化できる場合が多くなります。 「どの箇所にどんな修正がなぜ必要か」をかなり具体的に切り出せるようになるということです。

修正が必要な箇所と、その意図をはっきり区分できるのだから、修正の妥当性や方針をissueで議論したり、必要だと判断できた修正を切り分けたり、そういった作業が現実的になります。 「じっくり読まなければ何となくいい感じ」にまで到達した原稿に対しては、issueやブランチを切ったうえで、それに従ってコミットを細かく管理したりPull Requestを発行したりするワークフローが可能だともいえます。

問題なのは、まだ「じっくり読まなければ何となくいい感じ」に到達していない原稿です。 この段階になっていない文章を読むと、「どの箇所にどんな修正がなぜ必要か」をはっきりとは明言しにくいけれど、とにかく何かしら修正が必要であると感じます。 経験上、この段階の原稿が抱えている問題の多くは、切り分けが困難な問題です。 そのため、バージョン管理という視点で考えると、作業を分担したり作業内容に応じたコミットやブランチを駆使しようという努力があまり実を結ばない気がしています。

表面的な問題:統一感と文の品質

「内容をすべて書き出した」時点での原稿は、ソースのバージョン管理という観点で見ると、下記のような問題を抱えている状態です。

  • 統一感がない
  • 読みにくい文がある「ように感じる」

統一感がない

「内容をすべて書き出した」時点の原稿で用字用語がきれいに整っているケースはまずありません。 言葉遣いや文体、文章の温度もまちまちです。 なんとなく統一感がない状態です。

用字用語が揺れているだけなら機械的に対処できる面はかなりあるし、そのためのツールもいくつかあります。 とはいえ、「いう」と「言う」の使い分けみたいな、書き手がふだんあまり意識せずに書いている表現ほど、自動的な統一だと不自然な結果になったり、そもそも自動化しにくいように思います。 結局、けっこうなボリュームの本を編集するときは、頭から読みながら気になった時点でgrepして全体に修正をかける、といった作業をある時点で誰かがやっています。 そして、この作業は、たとえば用語ごとに独立したコミットとして切り分けるのが案外と困難なのです。 しかも、経験上は切り分ける意味もほとんどありません。

文章の統一感を上げる作業を、独立した細かいコミットとして切り分けにくい(切り分ける意味があまりない)理由としていちばん大きいのは、単一の行に複数の用語揺れが混在するケースが珍しくないからです。 「行う」と「行なう」の揺れを正す作業と、「無い」を「ない」に開く作業を別々の人がやれば、「行なわ無い」という非標準的な表記を「行わない」に直すだけであっさり衝突します。

それでもコミットを細かく分割すべきという考え方もあると思いますが、個人的な意見としては、 これはソフトウェア開発で「関数の仕様を変更したので関数名と引数リストを同時に修正しなければならないが、コミットとしては関数名に対する修正と引数リストに対する修正とで区分する」みたいな話に近いと思っています。 つまり実質的には分割の意味がほとんどない。

もう一つの理由は、他の修正作業との関係です。 ソフトウェア開発でも、バグ修正とコーディング規約に合わせる作業を同時にやれば、同一の行に対して何度も修正、加筆、削除、入れ替えが発生し、そのため競合が発生しやすくなるでしょう。 文章でも、統一感を上げる作業を文章・段落・節全体などの見直し作業と同時にやれば、解消に手間がかかる競合が多発します。 そのため、たとえば「用字用語の統一」のためのブランチを切って作業し、後でPull Requestとして一発でマージ、といった理想的に見えるワークフローは、他の作業をまじめにやっているケースほど非現実的だと考えています。 この作業は、ブルトーザーで荒地を耕すようなものだと割り切って、見つけた誰かがmasterに対して随時pushしていくほうが経験上はうまくいきます。

読みにくい文がある「ように感じる」

プログラムなら、コンパイルして型エラーが出たりテストに通らなかったりすれば問題の位置がかなり絞り込めます。 文章でも、文法上のミスや文章の品質については、指摘して問題箇所を特定してくれるツールがいくつかあります(textlintとかRedPenとかJustRight!とかMS Wordの校正ツールとか)。 とはいえ、人間が読むために書いているものをチェックしようとしている以上、結局は誰かが読んで初めて見えてくる問題がかなりあるわけです。 文意に曖昧さがないかとか、語調が不自然でないかとか、そういう問題は実際に読んでみなければ見えてきません。

こういった問題を修正しようとして、「この文を読みやすくした」とか「文意をはっきりさせた」といった名目で局所的なコミットをたくさん作ってしまうと、あとで面倒なことになります。 というのも、文章を読むことで初めて見つかるような問題というのは、実際には文章レベルより上位の段落や節が抱える問題の一部であることが多いからです。 このような問題に対する局所的な修正コミットや、それを意図したPull Requestは、後述する「段落や節に対する俯瞰的な修正」のための作業と競合してしまいます。

このような競合では、「段落や節に対する俯瞰的な修正」のほうが修正として適切なことが多いので、「局所的な修正」の作業は単純に水泡に帰すことになります。 「じっくり読まなければ何となくいい感じ」未満の原稿では、「局所的な修正」は「段落や節に対する俯瞰的な修正」と競合するものだと考えたほうがいいでしょう。 この段階の原稿に対しては、コミットを小さくすることが正義とは限らないともいえます。 「段落や節に対する俯瞰的な修正」を先にやることにして、気が付いた局所的な問題はissueなどの形でコメントを残すのみにしておくのが無難かもしれません。

根本的な対策:段落や節にまたがる俯瞰的な修正

コードが適切にモジュール化されているソフトウェア開発であれば、それほど変更が衝突することなく、個々のモジュールに対する作業を別々の人が同時にできるでしょう。 文章でモジュールに相当するのは段落ですが、段落は互いに密に結合しているし、抽象的なインタフェースもないので、互いの順序や文章表現について同時に配慮が必要です。 そのため、段落ごとに執筆や編集を分担するという方法は、あまりいい結果になりません。 とりあえずまとまった量を読んでみないと問題を切り分けられないし、切り分けている途中で問題が直せてしまったりするので、 判断を下しながらある程度の範囲を集中して読み進める、という工程が必要になります。

で、そういう不備を直していると、結果としてまったく別の問題が解消されたりすることがよくあります。 段落がまるまる修正されたので誤植が消滅したとか、段落を直した結果としていまいち曖昧だった文意がはっきりしたとか、 リライトが必要と思われた節とほぼ同じ内容の説明が他の場所にあったので節ごと不要になったとか。 しかし、誰かが該当する文章を局所的に修正していたり用字用語の統一を全体にわたってかけたりしていると、当然、その部分で競合が発生します。

俯瞰的な修正の作業は、かなり大きな範囲全体でコミットとして意味を持つので、他でコミットされたりPull Requestされた局所的な文章の修正をこのコミットの内容と調整するのはけっこう厄介です。 経験上うまくいくのは、たとえば「1章の見直し」といった作業内容ベースでブランチを切り、別のブランチでの1章に対する修正は用字用語の統一くらいに留めておく(この程度なら手動でマージできる)というワークフローです。 修正する内容に対するブランチを作るのではなく、修正する範囲を区切るためにブランチを作るイメージです。 このブランチでは、最終的にmasterへと自動マージできるような状態を維持しながら(masterの内容をときどきmergeしながら)、修正作業を続けるようにします。

執筆・編集にとって最適(いまのところ)だと思っているGitワークフロー

以上、だらだらと背景を書いてきましたが、結論です。

「内容をすべて書き出した」状態から「じっくり読まなければ何となくいい感じ」ゾーンにもっていくまでの間は、各コミットに必要以上に意味を持たせることはあきらめましょう。 完全に正史モデルを採用する必要はありませんが、この段階は開墾地をブルトーザーで整地するようなものです。 「木を抜く」作業と「穴を埋める」作業は並行してできるわけではないし、あとから一方の作業だけをやり直したいことも通常はありません (将来もし穴が必要になるとしたら、それは別の作業として考えるべきでしょう)。 それなりの規模の区画ごとに、全体の出来を眺めつつ、もくもくと均していくのが現実的なはずです。

一方、「じっくり読まなければ何となくいい感じ」ゾーンまで到達した原稿は、問題とその対処がコミットとして明確に切り分けられるので、修正の意図をはっきりさせた最低限のコミットを作り、それをmasterにマージするようにしましょう。

まとめると、次のようなポリシーで執筆・編集をするのがよさそうだというのが現時点での結論です。

  • 「じっくり読まなければ何となくいい感じ」まで達している原稿は、これから入れる修正の意図を明らかにしたいので、issueで議論してからコミットしたり、ブランチを切ってPull Requestにしたりする
  • それ以前の段階では、用字用語統一、誤記修正、タグ追加などの作業はブルドーザーによる整形作業だと割り切り、細かく管理するのはあきらめる。経験上、どのみちrevertやrebaseが不可能な作業なので徒労に終わる。信頼できる担当者どうしで作業をしているなら、見つけた人がmasterに随時pushするのが、他の作業との競合を回避するためにも効率的
  • それ以前の段階における局所的な文章の修正は、「じっくり読まなければ何となくいい感じ」ゾーンまではissueやコメントに留める。それ以降はPull Requestにする
  • それ以前の段階における節以上の範囲におよぶ内容上の修正は、作業範囲を隔離するためのブランチを切って作業する(このブランチではmasterにおける用字用語統一などの修正を適宜取り込みながら作業をする。Pull Requestにしてからマージしてもよいし、手動でマージしてもよい)

このほか、本文では言及しませんでしたが、下記のようなポリシーも経験上は有効であると考えています。

  • 脚注追加のように独立性が高いコミットとして修正を加えられる場合には、どの段階でもPull Requestにしてよい
  • メタ情報を、永遠にマージしないブランチで管理することもできる。索引タグなどは本文にマージする必要がないかもしれない

余談:「じっくり読まなければ何となくいい感じ」に到達したことを知るには

というわけで、文章のバージョン管理では「じっくり読まなければ何となくいい感じ」に至る前後のフェーズでコミットに対する考え方を変えよう、というのが現時点での自分の結論なのですが、 そもそも原稿の状態がこのティッピングポイントを越えたことはどうやって知ればいいのでしょうか?

残念ながら分かりやすい指標はまだ手にしていません。 しかし、循環論法めいていますが、ほぼすべてのコミットの意図を明確にできるようになった原稿は「じっくり読まなければ何となくいい感じ」になっているといえそうです。 その瞬間に気づくためには、いま施している修正が他の修正に依存していないかどうかを常に意識しながらコミットを刻む必要があるのかもしれません。

2016/02/29

バイナリ化したデータ構造を外部のファイルに保存して、コンパイル時にHaskellソースに埋め込む

Haskellには連想配列のように使えるMapというデータ構造(Data.Map)があります。 実行中にキーと値を更新するつもりがなく、コンパイル時に生成される固定的なMapを実行時に毎回使うという場合には、 リテラルのリストをソースコードに書いてMapに変換して使うのですが、 リストのサイズが1万要素とかになるとソース全体が肥大化してコンパイルに無駄な時間がかかるようになります。 生のリストをコンパイルのたびになめる必要はないのだから、Mapに変換したデータを辞書のように外部に持っておいて、 それをソースから読み込んで使う方法があるに違いありません。(ようするに、RubyでいうMarshal、PythonでいうPickleがしたい、ということです。)

他のファイルの内容をHaskellソースに埋め込むには、一般にTemplate Haskellが必要です。 ありがたいことに、外部のファイルの内容をソースコードに埋め込む機能に特化したfile-embedという便利なパッケージが用意されているので、これをTemplate Haskellと一緒に利用してこの問題を解決してみました。

バイナリの辞書を作る

まず、外部に保持するバイナリ辞書を下記の手順で用意します。

  1. リストからMapを作る
  2. そのMapをバイナリ化する
  3. さらにGzipで圧縮
  4. 結果を別ファイルに書き出す

コードにするとこんな感じ。このコードはバイナリの辞書(Map)を生成するだけなので、コンパイルと実行はきっかり一回だけです。

mkdict.hs

{-# LANGUAGE OverloadedStrings #-}

import qualified Data.ByteString.Lazy as BSL
import qualified Data.ByteString.Lazy.UTF8 as BSLU
import qualified Data.Map as Map
import Codec.Compression.GZip (compress)
import Data.Binary (encode)

dictList :: [(Int, BSLU.ByteString)]
dictList =
  zip [1..] $
      (map BSLU.fromString ["西住", "武部", "秋山", "五十鈴", "冷泉", ...その他大勢 ]

main = do
  BSL.putStr $ compress . encode . Map.fromList $ dictList
  return ()

ここでのポイントは、Mapのもとになる連想リストに日本語などの多バイト文字列がある場合、Data.TextではなくData.ByteString.Lazy.UTF8を使うことです。 なぜData.Textが使えないかというと、バイナリ化に使うData.BinaryData.Textに対応していないためです。 また、Data.ByteString.Lazy.Char8ではバイト列がぶった切られて日本語の文字が壊れてしまうので、結果的にData.ByteString.Lazy.UTF8を使うしかありません。(ほかによい方法があったら教えてください)

バイナリ辞書をソースに埋め込んで使う

上記で生成したバイナリ辞書をdict.datのような名前でどこかに保存したら、 下記のようにしてHaskellソースに埋め込んで使います。

  1. embedFile関数にファイルを指定すると、Template HaskellのQモナドにくるまれたデータが返ってくるので、これを$(...)で取り出す(というかソースファイル中に接ぎ木する)
  2. 接ぎ木されるデータは正格なByteStringなので、fromChunksで遅延ByteStringに変換する(fromChunksはByteStringのリストをとるので、リストの文脈に入れるためにreturnしている)
  3. 圧縮された状態を解凍
  4. バイナリをほどく

getmessage.hs

{-# LANGUAGE TemplateHaskell #-}

import qualified Data.ByteString.Lazy as BSL
import qualified Data.ByteString.Lazy.UTF8 as BSLU
import qualified Data.Map as Map
import Data.FileEmbed (embedFile)
import Codec.Compression.GZip (decompress)
import Data.Binary (decode)

dictMap :: Map.Map Int BSLU.ByteString
dictMap = decode . decompress $ BSL.fromChunks . return $ $(embedFile "data.dat")

getMember id = putStrLn $ case Map.lookup id dictMap of
  Just x -> BSL.toString x
  Nothing -> error $ "No entry for " ++ id

実行結果

$ ghc mkdict.hs -o mkdict
[1 of 1] Compiling Main             ( mkdict.hs, mkdict.o )
Linking mkdict ...
$ ./mkdict > data.dat
$ ghci
GHCi, version 7.10.3: http://www.haskell.org/ghc/  :? for help
Prelude>  :l getmember.hs
[1 of 1] Compiling Main             ( getmember.hs, interpreted )
Ok, modules loaded: Main.
*Main> getMember 3
秋山
*Main> getMember 5
冷泉
*Main>

参考資料

Compiling in constants(Haskell Wiki)
Gzipしたバイナリデータのリテラル表現をソースに埋め込んでいる事例(そんな人間が見ても意味がないデータをソースに貼り付けるのはいやだ)。 バイナリ辞書をCに変換して利用する例も紹介されているけど。
Haskellでバイナリデータ(yuga/gist:8255552)
Data.Textに対応したバイナリライブラリがなさそうなんだなということが分かりました。
How to compile a resource into a binary in Haskell?(Stack Overflow)
file-embedパッケージの存在を知りました。

2016/02/21

ターミナルモードのEmacsでHaskellを書いているときに補完候補をポップアップしてくれるcompany-ghc

Haskellのコードを書くときは、Windows 10からTeratermでDebianサーバにSSH接続し、そこでEmacsを-nwで起動して使っています。 標準のhaskell-modeでとくに不満はないのですが、いちおうghc-modも入れていて、単純なエラーの確認にはとても重宝しています。 でも、ghc-modの補完機能はほとんど使っていませんでした。補完のためのコマンドが手になじまず、調べている間に手打ちしてしてしまうので、ちっとも身に付かなかったからです。

とはいっても、ある程度の量を書いていると、やはり手で打っているのではしんどくなってきます。何とかならないかなーと思っていたところ、company-ghcというものを発見しました。

Company GHC
https://github.com/iquiw/company-ghc

ターミナルで開いているEmacsでも、統合開発環境のような補完メニューを実現するcompany-modeというツールがあって、そのHaskell版をghc-modを介して実現するためのパッケージらしい。試しにインストールしてみたところ、こんなふうに、まるで統合開発環境のようになりました。これならぼくにも使えそう。

インストールと設定の概略

すでにghc-modを入れているなら、そのインストール時にEmacsのパッケージをMELPAから取得できる状態にしていると思います。その場合は、M-x package-installcompany-ghcを指定するだけで、必要なパッケージを含めてインストールしてくれます(したがって事前にcompany-modeを個別にインストールする必要もありません)。MELPAからパッケージを取得する設定にしていない場合は、init.elかどこかに以下を設定します。

(require 'package)
(add-to-list 'package-archives
  '("melpa-stable" . "http://stable.melpa.org/packages/") t)
(package-initialize)

無事にインストールできたら、まずはcompany-modeを有効にします。haskell-mode利用時のみ有効にすることも可能ですが、せっかくなのでグローバルに有効にしておきます。そのほうがCtrl-c Ctrl-lでGHCiを起動したときにも補完が効くようになるし、いろいろ便利なはず。

(require 'company)
(global-company-mode)
あとは下記のようにcompany-ghcを設定すれば完了です。
(add-to-list 'company-backends 'company-ghc)
(custom-set-variables '(company-ghc-show-info t))

これだけでもとりあえず動くはずですが、company-modeのパラメータを少しいじったほうが使いやすそう。

(setq company-idle-delay 0.5)          ; 補完候補を表示するまでの待ち時間
(setq company-minimum-prefix-length 2) ; 補完候補の表示を開始する入力文字数
(setq company-selection-wrap-around t) ; 補完候補のスクロールが末尾に到達したら先頭に戻る

さらに、補完候補がポップアップ表示される際の背景色などを好みで設定します。下記の設定に加えて、Teratermの[ウィンドウの設定]で「256色モード(xterm形式)」にチェックが入っていて、かつサーバ側の環境変数TERMxterm-256colorに設定されていないと、とても日常の使用には耐えない悲惨なユーザインタフェースになってしまいます。

(set-face-attribute 'company-tooltip nil                  ; ポップアップ全体
  :foreground "black" :background "ivory1")
(set-face-attribute 'company-tooltip-common nil           ; 入力中の文字列と一致する部分
  :foreground "black" :background "ivory1")
(set-face-attribute 'company-tooltip-selection nil        ; 選択項目の全体
  :foreground "ivory1" :background "DodgerBlue4")
(set-face-attribute 'company-tooltip-common-selection nil ; 選択項目のうち入力中の文字列と一致する部分
  :foreground "ivory1" :background "DodgerBlue4")
(set-face-attribute 'company-preview-common nil           ; 候補が1つしかなくて自動で入力される場合
  :background "black" :foreground "yellow" :underline t)
(set-face-attribute 'company-scrollbar-fg nil             ; ポップアップのスクロールバー
  :background "Midnight Blue")
(set-face-attribute 'company-scrollbar-bg nil             ; ポップアップのスクロールバー
  :background "ivory1")

これで、最初の例のように、いい感じに補完候補が表示されるようになりました。

ちなみに、上記の色の設定例で「候補が1つしかなくて自動で入力される場合」とあるのは、下記のように候補が決定的になった状況のことです。

項目を選択した状態で[F1]を押すと、その項目のヘルプも見られます。

関係ないけど、TeXも捗る。

2016/02/09

LaTeXで連番リストに丸数字(\ajMaru)を使えたはずだけどhyperrefで困る話

LaTeXで丸数字の連番リスト環境の基本

そもそもLaTeXで丸数字を使いたいときは、otfパッケージajmacros.styの機能を使うのが一番お手軽です。 このスタイルでは、数値を指定してさまざまな囲み数字のグリフ(あれば)を呼び出すという便利な機能が提供されています。 たとえば、ふつうの丸数字であれば、\ajMaru{数値}として出力できます。

\ajMaru{1}、\ajMaru{100}、\ajMaru{101}

一方、enumerate環境でラベルのスタイルを変えたいときは、\theenumiとか\theenumiiといったコマンドを再定義します。 \theenumi\theenumiiは、それぞれ「enumi」や「enumii」という名前のカウンタに対応した「アラビア数字」に展開されるコマンドです。 その結果がenumerate環境でラベルを表示するのに使われているので、これらのコマンドの挙動を変えることで別の種類の数字を出力できるというわけです。 たとえばこんなふうにすれば、ラベルが大文字のローマ数字であるような連番環境が作れます。

\renewcommand{\theenumi}{\Roman{enumi}}
\begin{enumerate}
  \item 最初\label{A}
  \item\label{B}
\end{enumerate}
最初は\ref{A}、次は\ref{B}。

以上の知見を組み合わせれば、こんなふうにして丸数字の連番環境が作れそうです。

\renewcommand{\theenumi}{\ajMaru{enumi}}

しかしこれはうまくいきません。\ajMaruの引数は数値でなければならず、enumiはあくまでもカウンタの名前だからです。

ではどうすればいいかというと、ajmacros.styに用意されている\ajLabelというコマンドを使います。 このコマンドは、後続の\ajMaru{enumi}の中身を実際のカウンタ値として取り出してくれるように定義されています。

\renewcommand{\theenumi}{\ajLabel\ajMaru{enumi}}
\begin{enumerate}
  \item 最初\label{A}
  \item\label{B}
\end{enumerate}
最初は\ref{A}、次は\ref{B}。

hyperrefと一緒に使えなくなっているっぽい(2016年2月現在)

本当ならこれで話は終わりのはずなんですが、相互参照をクリッカブルにしてくれるhyperrefパッケージを同時に使うと話がややこしくなります。 hyperrefは、相互参照をクリッカブルにするためにカウンタ関連の機能をいろいろ勝手にオーバーライドするという鬼仕様なのですが、 ajmacros.styではそれに振り回されないように、 hyperrefを読み込んだ場合には\begin{document}の時点で\ajLabelなどをhyperref用にカスタマイズし直してくれます。

しかし、さらに厄介なことに、hyperrefはときどき内部の振る舞いをドラスティックに変更します。 そのため、せっかく再定義されている\ajLabelがまた使えなくなるという事態が2016年2月現在では発生しているようです。 具体的には、以下のような例で、上記のような事情を理解していないとちょっと追跡しにくいエラーが起きます。

\documentclass[dvipdfmx]{jsarticle}
\usepackage{otf}
\renewcommand{\theenumi}{\ajLabel\ajMaru{enumi}}
\usepackage{hyperref} % hyperrefを使う
\begin{document}
\begin{enumerate}
  \item 最初\label{A}
  \item\label{B}
\end{enumerate}
最初は\ref{A}、次は\ref{B}。
\end{document}

実行例

...
! Undefined control sequence.
\ajLabel ...abel \@arabic \else \Hy@ReturnAfterFi
                                                  \hyperref@ajLabel #1\fi {
l.17  \item 最
              初\label{A}
?

エラーが起きている\Hy@ReturnAfterFiは、かつてはhyperref.sty内で定義されて使われていたようですが、現在のhyperrefでは使われていないため、このような事態になってしまうようです。hyperrefパッケージのSVNのログを見ると、どうやら2011年4月に消えたようですね。

[hyperref-svn] oberdiek: r1291 - trunk
http://mail.gnu.org.ua/mailman/listarchive/hyperref-svn/2011-04/msg00002.html

上記のログを見る限り、oberdiekバンドルのltxcmdsパッケージで定義されている\ltx@ReturnAfterFiを使うようにしたので、\Hy@ReturnAfterFiをディスコンにしたようです。 \ajLabelの再定義では、この\Hy@ReturnAfterFiを利用しているので、上記の例がうまく処理できない結果になっているようです。

そこで、\Hy@ReturnAfterFi\ltx@ReturnAfterFiに変更するだけの以下のパッチをajmacros.sty(1.7b6)に当てて試したところ、意図した挙動に戻りました。 (\Hy@ReturnAfterFi\ltx@ReturnAfterFiの定義は同一なので当然といえば当然なのですが。。)

--- ajmacros.sty.org    2016-02-09 16:16:17.700785982 +0900
+++ ajmacros.sty        2016-02-09 16:15:57.548561902 +0900

@@ -685,7 +685,7 @@
 %      \def\check@UTF##1##2##3{\ifx\UTF##1\0x##2\else##3\fi}}{}}
 \gdef\ajRedefine@ajCommands{\@ifpackageloaded{hyperref}{%
        \let\hyperref@ajLabel\ajLabel
-       \def\ajLabel##1##{\ifHy@pdfstring\Hy@ReturnAfterElseFi\hyperref@ajLabel\@arabic\else\Hy@ReturnAfterFi\hyperref@ajLabel##1\fi}%
+       \def\ajLabel##1##{\ifHy@pdfstring\Hy@ReturnAfterElseFi\hyperref@ajLabel\@arabic\else\ltx@ReturnAfterFi\hyperref@ajLabel##1\fi}%
        \ajRedefine@ajCommand\"${Lig"$}\"&{Lig"&}\!*{Lig>.}\ajLig{Lig}\ajPICT{PICT}\"({PICT}\ajVar{Var}\@nil\@nil
        \aj@Redefine@ajCommand!{{Maru}!|{KuroMaru}""{Kaku}"#{KuroKaku}!~{MaruKaku}"!{KuroMaruKaku}\@nil\@nil
        \def\!J##1!K{\ifHy@pdfstring(##1)\else\expandafter\ifx\csname ajLig(##1)\endcsname\relax\@ajnumber{##1}{Kakko}%

hyperrefは、電子書籍をLaTeXで制作するうえでは唯一無二のパッケージなのですが、ときどきこういう面倒が起きるのがつらい。。

まとめ

またhyperrefか。

2016/01/27

技術書編集者として「これはやられた!」2015年の本

技術書の年間ランキング的なものについて、編集者たちに「これはやられた!」と思う他社の本を候補として出させたら面白いのでは、という会話を小耳にはさみました。これはまたとないアマゾンアソシエイトの機会!ということで、勝手に自分の候補を上げてみます。

と思ったものの、新刊の技術書をそんなにたくさん読んでいないうえに、去年「これはやられた!」と思った本はいずれも技術書ではなく、どちらかというと数学書っぽい本ばかりでした。それでも、ジュンク堂池袋本店の「新春座談会 このコンピュータ書がすごい! 2015年版」で取り上げられた本ばかりだし、たぶん技術者が読む(べき)本としても妥当なはずです。

コンピュータは数学者になれるのか? -数学基礎論から証明とプログラムの理論へ-

いま自分の本棚を見返したら、この本の隣にたまたま『日本の著作権はなぜこんなに厳しいのか』が並んでいて、一瞬だけ姉妹書に見えました。疑問形タイトル、文芸系とかビジネス系の出版社だと割と普通に見かけるけど、自分で本を企画するときには扱い方がわからず避けてしまうので、そういう書名を使いこなせる編集者になりたいです。というか、たぶん疑問形タイトルって、「これは既成の考え方をなぞった本ではなく、なおかつ人類は読むべきである」ことについて相当な自信がないと付けられない書名な気がします。

この本の場合、コンピュータと数学者のことを「算術計算に秀でたモノ」と考えている人にとっては、確かに「既成の考え方をなぞった本」ではないのでしょう。しかし、コンピュータとは自分が考えたプログラムが本当に動くことを確かめるためのものであるという人や、数学者はコーヒーから証明を生成する仕事であると気づいている人にとっては、どこかで見聞きして知っていたり知らなかったりする話にぐさっと明快な筋道を通してくれる本でした。一般向けの数学の読み物で見かける話も含まれてますが、call/ccは背理法ありの古典論理で純粋関数型言語は直感主義論理に対応しているんだという第5章のクライマックスに至る話を素で楽しめるのは、実際にプログラムを書いている技術者の特権だろうと思います。

出版社は青土社です。選択公理の読み物として一部で有名な‟The Pea and the Sun: A Mathematical Paradox”(Leonard M. Wapner)の翻訳である『バナッハ=タルスキの逆説 豆と太陽は同じ大きさ?』をはじめ(原書しか読んでないので翻訳の出来は知らない)、意外に「え?」っていう理学系の本も出してくるし、割と好きです。「現代思想」とか「ユリイカ」でも思想的な文脈で現代数学の記事をたまに掲載しているし、そのうち計算機科学や機械学習の特集もあるに違ない。

圏論の歩き方

Haskellを使うのに圏論はいらないって言うけど、みんな圏論圏論って言ってるので、どうしたって圏論が気になりますよね。そんな人間を狙いうちする本が日本評論社から発売されました。タイトルどおり、圏論の名所をめぐるツアーガイドのような本です。いつか自分の足で行ってみたいけど余裕がなくて行けない場所へ行った気になれる本です。去年の夏に読んで、いまこうやって記事を書くつもりで内容を要約しようとしても、さっぱり具体的な言葉にできないんですが、そのへんもツアーガイドに似ています(実際、「地球の歩き方」なんかにしても、行く場所を決めるときに読んだ内容をあらためて説明しろと言われても言葉に詰まりそう)。

正直、この本のうち計算機に関する部分については、まさに自分でこんな本を作りたかったという気にさせてくれる本でした。この本が企画として面白いと思うのは、コンピュータ書でいえばフレームワークに対する「クックブック」のような本を、数学の一分野で形にしてしまった点です。数学書、コンピュータ書でいえば「コードの動作について説明しただけ」だったり「コード読めばわかるよね」だったり、そんな立ち位置の教科書が少なくない気がします。コンピュータ書の場合には、実行例を見せることで「どんな場面でどんなコードが必要なのか」を説明できたりしますが、それを数学書でやったのがこの本なのかなあと思いました。いわば「圏論の実行例」。あるいは「圏論のクックブック」。もし何らかの事情で圏論について本当に「わかる」必要があるなら、体系的に書かれた教科書を読みながら紙と鉛筆で勉強するのが近道なんですが、そうやって教科書の証明を読み進めるときの「実行例」だけが本として、しかも圏論みたいな分野で出たということで、自分のなかでは「これはやられた!」一冊でした。

あなたの知らない超絶技巧プログラミングの世界

自分が過去に企画にできなかった本が企画化され、しかも想像以上に出来がいいのだから、「これはやられた!」一冊として選ばざるをえない。発売当時、くやしさをばねに紹介記事を書いたので、そちらを読んでください。

2016/01/08

英数字文字列を任意位置で改行するTeXパッケージを使う話

技術系のドキュメントでは、長い連続した英数字からなる文字列を等幅フォントで組む必要に迫られることが多々あります。 本文中にそんな文字列が連続して出現する原稿を、字間が異常に空いたり版面をはみ出したりすることなく組版するためのベストプラクティスは、有識者の間でも意見が分かれるようです。 うまく自然な改行位置に収まるように原稿のほうに手をいれられればベストですが、政治的経済的な理由で困難だったり、そもそも解説内容からして無理筋という場合もあります(Javaの変数名とかJavaの変数名とか)。

よくあるのは、空白やハイフンや記号文字の直後に恣意的な改行位置を指定する、という方法でしょう。 変数名を英単語の組み合わせだとみなすなら、この方法が自然に思えます。 キャメルケースの大文字の手前を恣意的な改行位置にすることもありうるでしょう。

しかし、「英単語として有意味な改行位置」は、このような文字列にとって必ずしも適切な改行位置ではないはずです。 たとえば、空白とかハイフンで区切ってしまうと、文字列のその部分に文字通り空白やハイフンがあるのか、たまたま改行があって空白やハイフネーション記号が挿入されているのか、区別しにくくなります。 キャメルケースの大文字の手前で改行されていると、その位置に文字通りの空白が入る可能性が気になって仕事になりません。 もちろん読者として読むなら意味を考えて区別できるんですが、作り手側にいると「勘違いして読まれたらまずいのでは」という不安をぬぐえないということです。

で、最近は、任意の文字間で改行するという思い切ったルールにするほうが理に適っているのではないかと考えるようになりました。 つまり、英数字の文字列ではあるけど、日本語や中国語のように組むわけです。 任意の音節区切りで改行くらいのほうが穏当な気もしますが、Webページだとword-wrap: break-word;が指定されている例も見かけるし、これをTeXでやってみようというのが本題です。

結論から言うと、seqsplitというパッケージがあります。もともとはDNAなんかの塩基配列を組むためのパッケージで、TeX Liveにも入ってます。 つまり、acgtの4文字からなる長大な文字列をページに組むことを目的にしています。 これを以下のような感じに使うことで、任意の位置で改行可能なバージョンの\textttが実現できます(実行例

\usepackage{seqsplit}
\usepackage{fancyvrb}
\VerbatimFootnotes

\makeatletter
% \def\seqinsert{\ifmmode\allowbreak\else\hspace{0pt plus 0.02em}\fi
\def\wordwraptt{\begingroup\obeyspaces\do@codeline}
\def\do@codeline#1{\texttt{\seqsplit{#1\relax}\endgroup}}
\makeatother

\begin{document}

Wikipediaによると、Brain*uckでは
\wordwraptt{%
++++++++[>++++[>++>+++>+++>+<<<<-]%
>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>%
.<-.<.+++.------.--------.>>+.>++.%
}というHello World!プログラムが書けます。

\end{document}

fancyvrbパッケージを読み込んでいるのは、\VerbatimFootnotesを使うためです。 このコマンドが提供するような仕組みがないと、\wordwrapttを脚注に配したときにスペースがなくなってしまいます。

改良したい点として、事前に中身の文字列を数えてあまり短いものは改行しないようにするといった処理もしたほうがよさそう。 (\penaltyによる調整は試してみたけれどあまりうまくいかなかった。)

なお、上記のような異常ケースでない場合は、Listingsというパッケージを使って\lstset{breaklines=true, breakatwhitespace=true}という設定をしてあげることで、そこそこ妥当な結果になるかもしれません。

(追記)さっそく改良案をいただきました。

あながちネタでもないと思っていて、似たようなことは考えていました(さすがに雪だるまをつかう発想はなかったけれど)。 上の例のコードブロックではコメントアウトしてある\seqinsertの再定義部分を書き換えると、このようなことが可能になります。


宣伝

TechBoosterがC89で頒布した6点のラインナップでは、上記のような仕組みを使うことで、Re:VIEWからでは制御困難な長い変数名の折り返し調整をなんとかしてみました。 が、コマンド中のスペースの存在を根本的に見逃すという大変残念かつ申し訳ない失敗をしています。本当にすみません。 電子版はなおっているはずなので、本誌に挿入されているQRコードでぜひ電子版も入手してください><

TechBooster in C89 特設ページ

というわけで、いろいろ微妙なTeXマクロだけど(LaTeXのことは知らない)、冒頭のツイートで思い出したのでネタとして。

2015/12/29

2016年賀状

年賀状書いた。
%!PS
(ps3d.inc) run
<< /PageSize [285 420] >> setpagedevice

-70 0 100 translate3d
[0 0 690 2] set-eye
[2 1 0.5] -45 rotate3d

/setrandcolor { % def
    /r1 {rand 5 mod 3 div} def
    /r2 {rand 4 mod 4 div} def
    /r3 {rand 3 mod 4 div} def
    r1 r2 r3 setrgbcolor
} def

/DS-Chocolade findfont [140 0 0 400 0 0] makefont setfont

1 1 20 { % for
  newpath
  0 1 20 { % for
    /y exch def
    0 y 320 mul moveto
    (2016) true charpath
  } for
  2d-path-convert
  clip
  gsave

  newpath
  0 20 300 { % for
    /x exch def
    /w 20 def
    gsave
      x 0 0 moveto3d
      x w add 0 0 lineto3d
      x w add 6000 0 lineto3d
      x 6000 0 lineto3d
      x 0 0 lineto3d
      closepath
      setrandcolor
      fill
      grestore
  } for

  grestore
  0.7 0 0.1 setrgbcolor
  stroke
  showpage
} for

2016.pdf by Keiichiro Shikano

今年はBill CasselmanさんのPostScript用3Dライブラリ ps3d.inc を利用しました(参照)。 使っているフォントは DS Chocolade。 スターウォーズは関係ないんだからね。

ps3d.inc はとても読みやすいソースで、しかも開発者のBillさん自身が Mathematical Illustration という本でわりと丁寧にマニュアルっぽいものを書いてくれているので、PostScriptで3Dを描いてみたい人にはお勧めです。 この本自体も、PostScriptを書きながら初等幾何も学べるという、実に面白い内容です(年に一回しか開かないけど)。 ただ、概説より先の解説はちょっと端折り気味なので、結局はこのライブラリの技術的根拠になっている Jim Bulin's Corners 1 も参照するはめになったけどな! ちなみに、Jim Bulin's Corners の vol.1 は元同僚が翻訳書(アフィリエイト)を出したので日本語で読めるんです。すごい。

過去のやつ。

2015/12/24

Re:VIEWな原稿のためのTeXフォーマットを作ってみたよ

tl:dr
  • これはTeX & LaTeX Advent Calendar 2015の24日目の記事である
  • Re:VEIW、LaTeXでPDFを作るんなら、そもそもRubyもRe:VIEWそのものも不要じゃない?
  • そこでRe:VIEW記法を直でコンパイルするTeXを作ってみた

(ここから本編)

今年の自分の仕事を軽く振り返ってみたところ、前職での最後の出版物となった『エクストリームプログラミング』をRe:VIEWを使って制作したり、無職になってから声を書けていただいた同人サークルTechBoosterの書籍制作でRe:VIEWが圧倒的に利用されていたり(年末のコミケで新刊解説書も売ってるよ!)、これまでになくRe:VIEWとの因縁めいた縁を感じる一年だった気がします。そこで、なにかRe:VIEWに関連したネタで記事が書けたらいいなあと思いました。

というわけで、TeX & LaTeX Advent Calendar 2015のためのネタとして、Re:VIEWとTeXがもっと仲良くなれるかもしれない方法を考えてみました。TeX & LaTeX Advent Calendar 2015の昨日12月23日の担当はdoraTeXさん、明日最終日の担当はzr_tex8rさんです。

さて、Re:VIEWの話を書くと決めたはいいものの、今年のTeX & LaTeX Advent Calendarには「今さら人に聞けない、TeXのキホン」という重点テーマが設定されています。Re:VIEWがTeXのキホンとは思えない。そこで、とりあえず形だけでも重点テーマを消化すべく、まずはTeXのキホンのひとつといえるアクティブ文字について説明することにします。TeXのキホンに興味がない人は「2. Re:VIEW風のシンタックスで書けるTeXを作ってみた」まで読み飛ばしてかまいません。

アクティブ文字とは

TeXとかLaTeXには、俗にいうマクロとかコマンドと呼ばれるものがあるのはご存じですよね。 バックスラッシュとか円記号の後ろに英文字が並んでるやつです。 このマクロとかコマンドを使って、ページに出力する要素の構造を指定したり、繰り返し入力する手間を省いたり、特殊な記号を入力したり、装飾を施したり、絵を描いたりできるのでした。

このマクロやコマンド、ほとんどの場合は「\から始まる文字列」(専門用語ではコントロールシーケンス)という形式の名前で定義するんですが、実はもう一つ方法があって、それが本節のテーマであるアクティブ文字です。 ようするに、単なる文字がまるでマクロやコマンドのように定義済みの内容に展開される機能がTeXにはあって、それをアクティブ文字と呼んでいます。

アクティブ文字「~」(チルダ)

アクティブ文字の代表例は「~」(チルダ)です。 ふつうのTeX環境における「~」には、HTMLにおける&nbsp;と同じく、ノーブレークスペースという機能が割り当てられています。 つまり、改行されるのは嫌だけどアキが欲しいような場所に「~」を挿入することで、TeXの組版処理を制御できます。

See Figure 1.1.  % 「Figure」と「1」の間で改行される可能性がある

See Figure1.1.   % 「Figure」と「1」の間で改行されないが、アキもない

See Figure~1.1.  % 「Figure」と「1」の間で改行されず、アキも入る

この挙動が、実はTeXの実装でハードコードされている機能ではなく、次のような感じでアクティブ文字「~」として「定義」されているというわけです。

\catcode`\~=13
\def~{\leavevmode\nobreak\ }

\catcodeというのが文字の種類(カテゴリコードと呼ばれています)を変更するためのTeXプリミティブで、「13」がアクティブ文字のカテゴリコードです。\catcodeで文字のカテゴリコードを13に変更すると、通常のコントロールシーケンス(バックスラッシュで始まる文字列で作れるやつ)とまったく同じ要領で、\defを使って動作を定義できます。

好きな文字をアクティブ文字に変更してみよう

もちろん、自分で好きな文字をアクティブ文字に変更して、その動作を好きなように定義することも可能です。 たとえば、「*」という文字を「\item 」に展開できると楽ができそうですよね。

\begingroup
\catcode`\*=13
\def*{\item }

\begin{itemize}
* 箇条書きが、
* こんなに、
* 書きやすく!
\end{itemize}
\endgroup
あるいは、文中の「8」という文字をすべて雪だるまにすると楽しそうですね(scsnowmanパッケージマジ便利)。
She's the last of the V8s!

\begingroup
\catcode`\8=13
\def8{\scsnowman[hat=true,muffler=red,arms=true]}

V8! V8!

\endgroup

問題は、こんなふうに気軽に「*」や「8」の意味を変えてしまうと、「*」や「8」という文字を本来の意味で使えなくなってしまうことです。とくに「*」は、文章中で使えないだけならまだしも(それだけでも困る場面はあるでしょうが)、\section*{連番なしの節タイトル}のような一般的なコマンドで使えなくなってしまうのは困ります。 実際、上記の2例では、\begingroup\endgroupを使うことで、これらがアクティブ文字として有効になるスコープを制限しています。

そんなわけで、こんなに便利で楽しいアクティブ文字ですが、ふつうにTeXやLaTeXで文章を書くときに利用できるものは最初に紹介した「~」のみです。残念ですね。 (改行文字を段落の終わりとして再定義して特定の環境内で暗黙に利用しているようなケースはあります。)

Re:VIEW風のシンタックスで書けるTeXを作ってみた

アクティブ文字で、なにかもっと面白いことはできないでしょうか。

前の節では、「*」という文字を再定義して\itemのように使う方法を紹介しました。 よく考えるとこれは、Re:VIEW記法における箇条書きのシンタックスそのものです。 ひょっとしたら、アクティブ文字をさらに駆使することで、バックスラッシュと波カッコというTeXやLaTeXの記法(悪名高い)に縛られずに原稿を執筆できるところまで持っていけるのではないでしょうか。いや持っていけるに違いない。

シンプルな箇条書きの記法

長い前置きはこれくらいにして、ここからはさまざまなRe:VIEW記法をTeXで実装していくことにしましょう。 まずはRe:VIEWの箇条書き記法をTeX上で再現してみます。

新しい段落が「*」で始まったらitemize環境に入り、新しい段落が出てきたら抜けて、その間に出てくる「*」は問答無用で\itemにするが、それ以外の「*」はそのまま印字する、という動作なら、*をアクティブ文字にしてこんな感じに書けそうです。

\newif\if@itemize
\chardef\active=13
\begingroup
\catcode`\*=\active
\gdef*{%
  \ifvmode\@itemizetrue\begin{itemize}
    \everypar={\end{itemize}\@itemizefalse}
  \fi
  \itemize@to@eol}%
\endgroup

\def\itemize@to@eol{\begingroup\catcode`\^^M=12 \@@itemize@to@eol}
{\catcode`\^^M=12 \catcode`\^^I=5 %
 \gdef\@@itemize@to@eol#1^^M{\review@itemize@head#1 \endgroup}}
\def\review@itemize@head{\if@itemize\item \else*\fi}

TeXやLaTeXのシンタックスは捨てることにしたので、ほかのコマンドに「*」が出てくる心配はいりません。 冒頭で\catcode`\*=\activeとして実際に文書を作成してみましょう。

ただしこの実装だと、同じ行に「*」が二回出てくるとおかしなことになったり、あとに何かしら段落が存在しないと意図しない結果になったりします。 本当ならもっと作りこむべきなのでしょうが、そもそも軽量マークアップ言語なんて制作者の技術的な都合で仕様が決まるものなんだから、ここはそういう仕様ということにして先に進みます。

Re:VIEWのインラインコマンド

Re:VIEWには@<command>{content}という形式のインラインコマンドがあります。 これを同様にアクティブ文字を濫用して実装してみましょう。

\begingroup
\catcode`\@=\active

\gdef\codereview{code}
\gdef\bfreview{b}

\gdef@<#1>#2{%
  \def\reviewname{#1}
  \ifx\codereview\reviewname\texttt{#2}\fi
  \ifx\bfreview\reviewname\textbf{#2}\fi}
\endgroup

こちらはTeXの記法に近い(?)ので比較的安直に実装できます。 上記では等幅にするコマンド(@<code>{...})と太字にするコマンド(@<b>{...})だけを定義していますが、必要に応じて好きなものを追加してください。

章見出しや節見出し

Re:VIEWでは「=」で行を書き始めると個数に応じて階層的なヘッダになります。 これをTeXで実装しましょう。めんどくさいですが、処理自体は素直なものです。

\begingroup
\catcode`\==\active
\gdef=#1#2{\let\@tmpa#1\let\@tmpb#2%
  \ifvmode \@headertrue\inc@header@cnt
    \ifcat\noexpand=\noexpand#1 \inc@header@cnt\let\@tmpa\relax
      \ifcat\noexpand=\noexpand#2 \inc@header@cnt\let\@tmpb\relax
  \fi\fi\fi
  \eq@protected\@tmpa\@tmpb}
\endgroup

\newif\if@header
\newcount\header@cnt
\def\inc@header@cnt{\global\advance\header@cnt by 1}
\def\reset@header@cnt{\global\header@cnt=-1}

\reset@header@cnt
\def\eq@protected{\if@header\proc@header\else =\fi}
\def\proc@header{%
  \expandafter\gen@header\header@cnt}
\def\gen@header#1{\@headerfalse%
  \ifcase #1 \review@chapter
  \or        \expandafter\review@section
  \or        \expandafter\review@subsection
  \fi\reset@header@cnt}
\def\review@chapter#1\par{\edef\chapstring{#1}\chapter[]{\chapstring}}
\def\review@section#1\par{\edef\sectstring{#1}\section[]{\sectstring}}
\def\review@subsection#1\par{\edef\subsectstring{#1}\subsection[]{\subsectstring}}
現状だとページの柱や目次に章タイトルを出力できないなどの問題は残っていますが、とりあえずできたということにします。
見出し行があるだけでずいぶんマークアップ言語っぽくなりますね。

Re:VIEWの環境

Re:VIEWでは//foo{から//}のような書式で特殊なスタイルのための環境を設定できるようになっています。 これもLaTeXの環境の記法に似ているので簡単に実現できるかなと思ったんですが、そもそもTeXには真のパターンマッチがないので、ややトリッキーな仕掛けが必要でした。

\begingroup
\catcode`\/=\active
\gdef//#1#{\begingroup\catcode`\/=\active\def//{}
  \csname review@#1\endcsname}
\endgroup

\long\def\review@list#1{\begin{alltt}#1\end{alltt}\endgroup}
\long\def\review@quote#1{\begin{quote}#1\end{quote}\endgroup}
\long\def\review@read#1{\begin{quote}#1\end{quote}\endgroup}
\def\review@footnote#1{\footnote{#1}\endgroup}

ここでちょっと悩ましいのが、よく似た記法を持つ//footnoteのようなRe:VIEWコマンド(波カッコがない点に注意)の存在です。これにも対応するには本気でパーザを書くことになりそうなので、//footnoteコマンドでもコンテンツは波カッコで囲むということにします。 つまり、この時点でRe:VIEWとは互換性のないシンタックスになってしまっていますが、軽量マークアップ言語なんて制作者の技術的な都合で仕様が決まるものなんだから(ry

あとなんかallttの中の改行処理がうまくいってないとか、入れ子への対応が不十分とか、課題は残ってるけど深追いしない。

Re:VIEWっぽい原稿をデフォルトでロードするTeXプログラムを作る

これらの定義をプリアンブルに書いたりスタイルファイルに書いたりして、LaTeXの \begin{document} ... \end{document} の間で実行するだけでも面白いといえば面白いのですが、どうせなら、.reファイルから直接PDFを組版できる独立したコマンドがあると便利ですよね。 というわけで、上記のマクロたちをフォーマットとしてまとめておきました。

revtex: TeX with Re:VIEW syntax
https://github.com/k16shikano/revtex

いちおう補足しておくと、TeXの文脈でフォーマットといったら、initexを使ってダンプする(あるいはダンプした)ファイルのことです。 そのフォーマットをデフォルトで利用するrevtexという新しいTeXの実行ファイルを作ることで、Re:VIEWっぽい記法の原稿を直接コンパイルできるようにしようというわけです。

日本語を組版したいので、ベースにするのはuplatexコマンドとします。 uplatexの実行ファイルをrevtexという別名で用意し、上記のフォーマットをかませて使うように設定すれば、こんなふうにTeXで直接、ほぼRe:VIEW記法の原稿をコンパイルできるようになります。

$ ls -la /usr/bin/revtex # revtexはuplatexのシンボリックリンク
lrwxrwxrwx 1 root root 16 Dec 22 12:28 /usr/bin/revtex -> /usr/bin/uplatex
$ cat sample.re          # sample.reは(ほぼ)Re:VEIW記法のファイル
= はじめてのUNIX

== 実際すごい

重金属を含んだ酸性雨が降りしきるなかをものともせず、
@<b>{マグロツェッペリン}//footnote{巨大飛行船}が回遊する!

* ネオサイタマ
* マルノウチ・スゴイタカイビル

その頂から退廃的な高密度ネオン看板が瞬く地獄めいた都市の喧噪を見下ろす影がひとつ急降下した。コワイ!

== もっとすごい

「こんにちはニンジャ・スレイヤー=サン。」
そういって敵は姿を見せぬまま@<code>{UNIX}端末にログインした。

= インガオホー

こんにちはダークニンジャ=サン。ハイクを詠め!

//quote{
トチノキ、フユコ……
}

#@# fin
$ revtex sample.re       # ほぼRe:VIEWな原稿がTeXでコンパイルされる
This is e-upTeX, Version 3.14159265-p3.6-u1.20-141210-2.6 (utf8.uptex) (TeX Live 2015/Debian) (preloaded format=revtex)
 restricted \write18 enabled.

kpathsea: Running mktexfmt revtex.fmt
...

いうまでもありませんがRubyもRe:VIEWも不要です。最後にdvipdfmxが何か言ってますが、無視する方向で。 生成されたPDFを以下に張っておきます。

画期的ですね。

実は、少なくともひとつ、どうにも解決できないダサい制限があって、原稿ファイルの末尾にオリジナルのRe:VIEWではコメントとして無視される「#@# fin」という行を書いておく必要があります。 TeXは組版をするとき、\endというプリミティブで原稿ファイルの終端に到達したことを知るのですが、Re:VIEWにはそのための記法がないので、こうしてお茶を濁しているわけです。

(追記) と思い込んでいたら、e拡張には\everyeofなるそのまんまなプリミティブがあると教えてもらいました。 これを使うと、確かに最後の行が不要になるので、ひそかにあきらめていた行コメントも実現できました。(追記おわり)

免責と今後の展望

auxによる参照解決とか、エスケープとか、いろいろさぼってるので実用品ではありません。 また、これ以上Re:VIEW対応率をあげようとか、バグを直そうとか、そういう予定もたぶんありません。 むしろ、あらためてMarkdownっぽいのを実装するほうが面白そうかも。

参考資料

TeX by Topic
TeX芸には欠かせない説明不要の名著。日本語訳もあるが入手は困難。原著者のサイトで英文なら全部読める。
1TeXの実装
TeX芸の北極。文字「1」をアクティブ文字にすることで、文字通り「1」のみでTeXコンパイル可能な文書を作る。
xmltexの実装
XML文書をTeXでコンパイルするという、海外のTeX芸のひとつ。
Re:VIEWフォーマットのドキュメント
これ以外にもいろいろ隠しコマンドがあるらしい。

2015/09/24

『あなたの知らない超絶技巧プログラミングの世界』は誰が読むべきか

遠藤侑介さんといえば、Quineをはじめとする変態プログラムの世界的なタツジンとして有名ですが、そのむかし遠藤さんに向かって「Quineの本とか、売れないことが確実ですね」という趣旨の発言をしたことがあります。遠藤さんがブログやコンテストで発表していた変態プログラムには個人的にとても魅力を感じていて、翻訳書で一緒にお仕事をする前から楽しませてもらっていたのですが、さすがに書籍の企画ネタにするのは難しいなあ(売れるようにするのが難しいという意味で)と思っていたのです。それから数年後、まさか本当にQuineの書き方の解説が載っている本が出版されるなんて! それもQuineのみならず、遠藤さんのネタを徹底解説するような本がでるなんて! 企画を担当した編集者もずいぶんな変態に違いありません。というわけで、今月発売された遠藤侑介著『あなたの知らない超絶技巧プログラミングの世界』という本をさっそく読みました(下のリンクはアマゾンで、9/24現在ではまだ予約中だけど、なぜか都内の大型書店にはふつうに配本されている)。

読んだといっても、ざっと目を通したレベルであって、内容をきちんと咀嚼できるほどには読み込んでいません。というか、本書の内容をきちんと咀嚼できる日が自分の人生にやってくるのだろうか、というのが率直ないまの気持ちです。なにせ本書は、いうなればリストやパガニーニが懇切丁寧に自分の楽器演奏テクニックを言語化して解説してくれているようなものです(実際、本書のタイトルの「超絶技巧」はリストの同名の練習曲に由来するようです)。あるいは、シューマッハが自分のドライビングテクニックを教本としてまとめてくれているようなものです。そんなもの、本を読んだくらいで習得できるわけがないじゃないか! その意味では、この本、けっして「わかりやすい」とは言えないと思います。むしろ「わからない」ことをわざわざ楽しむための本なので、「わかりやすくない」のが必然なんでしょう。解説自体はとても丁寧に書かれているので、必要になったときに必要な箇所を真剣に読めば大丈夫そうだなと判断して順調に読み飛ばしました。にしても、この本の内容が「必要になるとき」なんて自分にあるんだろうか……。(という読者の葛藤を見越して「必要になるとき」を強制発動するための「練習問題」がついているところに著者の心意気を感じました。)

「この本が必要なのは誰だろう」という、おそらく書籍企画にとって根源的な問題は、著者の遠藤さんをだいぶ悩ませたんではないかと思います。本文を読んでいると「実益は期待しないで」といった趣旨の開き直りにちょくちょく出くわすし、「まえがき」に至っては「実用性という観点は雑念」とまで言い切られています。でも、「雑念」だと言った鼻の先が乾かないうちに「ある種の気づきを与えてくれる」とか言って実用性がほのめかされています。

じゃあ、この本、いったい誰が読むべきなんでしょうか? 独断ですが、本書の対象読者は大きく次の3つに設定できる気がします。

1. 超絶技巧なプログラムをでたい人
たぶんこの本のいちばんありがちな楽しみ方は「めでる」でしょう。実際、第1章は超絶技巧プログラムを眺めて楽しむという位置づけだし、後続の章も眺めているだけで楽しくなります。『Core Memory ― ヴィンテージコンピュータの美』なんかと同様に、計算機とその周辺にある種の美を感じる人はとりあえず購入して損はしないはずです。
2. 超絶ではないにせよプログラミングの技巧に興味がある人
この本は、Quineのようなプログラムを書きたい人だけでなく、ある種の技巧的なプログラムを書きたい人にとってはそこそこ実用的です。たとえば、CUIのアプリでアニメーションをする方法のような実用的で具体的な内容が丁寧に解説されている本は、ほかにあまりない気がします。また、zlibを使わずにPNGを作る例など、プログラミングに必要な潔さ(教科書には書いていない)を学べます。プログラミングコンテストとかで応用できたりできなかったりする気がします。出たことがないので憶測です。
3. 計算機科学とか数学基礎論が好物な人
数学基礎論や計算機科学の深めの話に踏み込んだコラムの数々が実に有益な読みどころです。Quineの存在証明をRubyで書き下してくれている本なんて、たぶん世界中でほかにはなかったし、これからもないと思います。デュードニーの『チューリングオムニバス』とか、まだ翻訳が出ていないけど『Good Math: A Geek's Guide to the Beauty of Numbers, Logic, and Computation (Pragmatic Programmers)』とかが大好きな人はコラムだけでも興奮できると思います。

無理やりまとめると、本書は(ほぼ)世界一の人がそのテクニックを披露し、伝授してくれて、さらに深堀するという貴重な本です。遠藤さんが書いたこの本を読みたい人は世界中に少なからずいるでしょう。いまのところ本書は日本語でしか楽しめないので、日本語ネイティブで本当によかった。9月28日にはジュンク堂池袋店でサイン会もあるそうなので、Quineなサインをもらいにいこうと思います。

なお、全体を通してRubyがメインで使われているので「Ruby限定の内輪テクニック集」に見えるかもしれませんが、それに終始する本ではないのはさすが遠藤さんだと思いました。唯一残念なのは索引がないところです(上記の2と3が対象読者なら必須だと思う)。あと細かい話ですが、Paul Grahamのカタカナ表記は「ポール・グレアム」のほうがいいと思いました。

2015/09/10

Wikipediaのエントリを束ねてEPUBを作れるようにしてみた

Wikipediaには好きなページを集めて本を作れる機能があります。左側のメニューにある[印刷/書き出し]から[ブックの新規作成]というメニューをクリックすると、それ以降に閲覧する各ページで「ブッククリエーター」というツールバーが以下のような感じで有効になって、そのツールバーで自分が本に収めたいページを追加していけるという機能です。追加したページを並べて自分だけのオリジナルの本が作れます、というサービスです。

で、何年か前はこのブッククリエーターの出力形式としてPDFのほかにEPUBを選べたのですが(参考)、いつの間にかPDFとプレーンテキストのみになってしまっていてEPUBを作れません。これは日本語版だけでなく英語版でも同様です。

べつにWikipediaをEPUBで読めないからといって困ることはないのですが、自分が開発して自分で使っているEPUB作成ツールのテスト用にWikipediaのページを使えたらいいなと思って、Wikipediaのエントリをいくつか指定してEPUBを生成できる仕組みを作ってみました(参考)。動機が動機なのでローカルでのみ使うつもりだったのですが、AWSでデモが動くようにしてみました(ただしエントリの上限を3つにしているので3章までの本しか作れません。ダウンしてたらごめんなさい。あと英語版Wikipediaのみに対応)。

以下のような感じにEPUBが生成されてダウンロードできるようになるはずですが、Mediawikiのパーズで力尽きたので、WebアプリとしてもEPUBジェネレータとしてもまだぐだぐだです。低品質の勧めに従って公開してみます。

2015/09/01

職務経歴書

いろいろあって職務経歴書を作成してみることにしました。お便りお待ちしています!

要約すると

理工系出版社の開発部という部署で約13年間半、主にコンピュータネットワークとプログラミングの本を企画し、制作してきました(企画制作に携わった主なコンテンツ」および「企画者として公式に社内に名前が出ている、かつ、制作でも中心だった書籍の一覧」を参照)。 特にTCP/IP関連書籍と、翻訳技術書は、たくさんの技術者の方に手に取ってもらえた(願わくば役に立てた)と思います。

読者が読んだことを後悔しない本を作るのは当然として、著者や訳者が出版したことを後悔することがないように、編集制作プロセスの透明化にも努めました。 通常、著者や訳者は、出版物に対する責任があるにもかかわらず、その最終的なデータを手にすることがありません。 著者による校正の終了後に編集者が内容のデグレにつながるような修正を勝手に加えてしまった、という話もよく聞きます。 そのような悲劇を駆逐するため、すべての制作データをSubversionやGitのリポジトリを介して著者と最後まで共有し、ありとあらゆる編集内容が全員にとって透明な制作フローを採用しました(バージョン管理システムを利用した制作システムの開発・運用」を参照)。

この制作フローにとって欠かせないのが、誰かが作業をリポジトリに反映するたびに最終的な本と同じ組版結果が自動的に生成される仕組みです。 書籍の構成や組版は毎回異なるので、そのような仕組みを実際の現場で運用していくために、自分でカスタマイズしやすい自動組版システムを開発しました(社外での活動」を参照)。 必然的に、プロジェクト単位ではありますが、夢のワンソース・マルチアウトプットも実現しました。 直近の書籍の多くでは、印刷用PDFとデータ販売用PDFに加え、EPUBも単一のソースからmake一発で生成しています。

さらに、TracのチケットやGitHubのissueおよびPull Requestを活用することで、編集に必要な意見のすり合わせにかかるコストを大幅に低減しました。

これらの取り組みにより、原稿の頻繁な見直しが可能になったことで、書籍の品質が大きく向上しました。 著者と編集者(組版者)との意思疎通に起因する書籍の不具合もほぼゼロにできました。 多人数が同時に並行して書籍制作に関与できることから、外部レビュアーによる協力も得やすくなり、書籍内容のさらなる改善にもつながりました。 書籍制作にかかる時間的および金銭的コストも大幅に削減できました。

制作に携わった書籍のプロモーションも積極的に行いました。 いまどき、どんなに自分が良い本を作ったつもりでも、潜在的な読者にその本の存在が伝わらなければ読んでもらえません。 書籍の内容を、必要な人に、できるだけ魅力的に伝えるべく、会社のブログや個人のツイッター/ブログ(これな)を使ってアピールしました。

もう一つ、自分の企画や制作とはまったく別の話として、他者の企画書籍に対するサポートにも貢献しました。 具体的には、著者あるいは原稿にとって適切な目次構成案を提案したり、より販売力のある書名を考案したり、カバーの選定に協力したりしました。 特にマンガを用いた技術書シリーズでは、コンセプトに対する提言やコンテンツの技術査読を担いました。

企画制作に携わった主なコンテンツ

以降、書籍などのリンク先は、無職につきすべてAmazonアソシエイトです。

バージョン管理システムを利用した制作システムの開発・運用

  • 原稿執筆段階から印刷所入稿に至るまで、すべての制作データをGit/Subversionを利用してバージョン管理
  • それを実現するため、原稿の多様なマークアップに対応可能なXML→LaTeX変換プログラム(後述するxml2tex)を利用した自動組版システムの構築
  • LaTeXを含む多彩なマークアップ原稿からのEPUB生成
  • LaTeX組版用の標準的なクラスファイル作成

geekなページのあきみちさん(『インターネットのカタチ―もろさが織り成す粘り強い世界―』の主著者)が、この制作フローについてのわかりやすい説明記事を書いてくださいました(「svn+TeXでcommitするとPDF - オーム社開発部の出版システムでの書籍執筆」)。ただし原稿の形式は(La)TeXとは限りません。また、ちょっと前の記事なのでSubversionベースとなっていますが、最終的にはGitHubベースのシステムを使っていました)。

社外での活動

  • XML風のデータ構造を、直感的なルールにより任意のマークアップへとシリアライズするためのプログラム xml2tex の開発
  • 野良XMLを束ねてEPUB化するためのプログラム qnda の開発
  • 2013年TeX User Group年次総会でのチュートリアル講演("Index makes your book perfect"

企画者として公式に社内に名前が出ている、かつ、制作でも中心だった書籍の一覧

2006年以降は、ほとんどの制作も自分でやっています(自動組版でな)。 このほか、企画に名前が出ているけど制作はほかの人がやった本、どこにも名前が出ていないけど全部制作した本、タイトルや目次構成を提供した本、技術査読をした本などが無数にあります。

  1. エクストリームプログラミングKent Beck, Cynthia Andres, 角 征典, 2015/6/25
  2. 基礎からわかるTCP/IP ネットワークコンピューティング入門 第3版 村山 公保, 2015/2/25
  3. 関数プログラミング 珠玉のアルゴリズムデザイン, 山下 伸夫, 2014/11/11
  4. 新装版 リファクタリング―既存のコードを安全に改善する― (OBJECT TECHNOLOGY SERIES) Martin Fowler, 児玉 公信, 友野 晶夫, 平澤 章, 梅澤 真史, 2014/7/25
  5. すごいErlangゆかいに学ぼう! Fred Hebert, 山口 能迪, 2014/7/3
  6. たのしいプログラミング Pythonではじめよう! Jason R.Briggs, 磯 蘭水, 藤永 奈保子, 鈴木 悠,2014/2/25
  7. マスタリングTCP/IP 情報セキュリティ編 齋藤 孝道 2013/8/30
  8. マスタリングTCP/IP OpenFlow編 あきみち, 宮永 直樹, 岩田 淳 2013/7/25
  9. マスタリングTCP/IP IPv6編 第2版 井上 博之, 黒木 秀和, 小林 直行, 志田 智, 鈴木 暢, 矢野 ミチル 2013/7/23
  10. 型システム入門 −プログラミング言語と型の理論− Benjamin C. Pierce, 住井 英二郎, 遠藤 侑介, 酒井 政裕, 今井 敬吾, 黒木 裕介, 今井 宜洋, 才川 隆文, 今井 健男, 2013/3/25
  11. ディジタル作法 −カーニハン先生の「情報」教室− Brian W. Kernighan, 久野 靖, 2013/2/25
  12. レジデント初期研修用資料 内科診療ヒントブック 改訂2版 medtoolz 2012/11/22
  13. 関数プログラミング入門 ―Haskellで学ぶ原理と技法― Richard Bird, 山下伸夫, 2012/10/25
  14. すごいHaskellたのしく学ぼう! Miran Lipovača, 田中 英行, 村主 崇行, 2012/5/22
  15. マスタリングTCP/IP 入門編 第5版 竹下 隆史, 村山 公保, 荒井 透, 苅田 幸雄 2012/2/24
  16. RailsによるアジャイルWebアプリケーション開発 第4版 Sam Ruby, Dave Thomas, David Heinemeier Hansson,前田 修吾, 2011/11/30
  17. 抽象によるソフトウェア設計−Alloyではじめる形式手法− Daniel Jackson中島 震, 今井 健男, 酒井 政裕, 遠藤 侑介, 片岡 欣夫,2011/7/14,
  18. インターネットのカタチ―もろさが織り成す粘り強い世界― あきみち, 空閑 洋平 2011/6/24
  19. Scheme修行 Daniel P. Friedman and Matthias Felleisen, 元吉 文男, 横山 晶一, 2011/6/14
  20. Coders at Work プログラミングの技をめぐる探求 Peter Seibel, 青木 靖, 2011/5/24
  21. レジデント初期研修用資料 医療とコミュニケーションについて medtoolz 2011/1/24
  22. Scheme手習い Daniel P. Friedman, Matthias Felleisen, 元吉 文男, 横山 晶一, 2010/10/22
  23. 関数プログラミングの楽しみ Jeremy Gibbons and Oege de Moor, 山下 伸夫, 2010/6/22
  24. レジデント初期研修用資料 内科診療ヒントブック medtoolz 2010/3/19
  25. 情熱プログラマー ソフトウェア開発者の幸せな生き方 Chad Fowler, でびあんぐる, 2010/2/25
  26. RailsによるアジャイルWebアプリケーション開発 第3版 Sam Ruby, David Heinemeier Hansson, Dave Thomas,前田 修吾,2009/11/30
  27. プログラミングHaskell Graham Hutton, 山本 和彦, 2009/11/10
  28. プログラミングのための確率統計 平岡 和幸, 堀 玄 2009/10/22
  29. 入門git Travis Swicegood , でびあんぐる, 2009/8/11
  30. Release It! 本番用ソフトウェア製品の設計とデプロイのために Michael T. Nygard, でびあんぐる, 2009/2/20
  31. Manage It! 現場開発者のための達人式プロジェクトマネジメント Johanna Rothman, でびあんぐる, 2008/10/17
  32. 実践Common Lisp Peter Seibel, 佐野匡俊, 水丸淳, 園城雅之, 金子祐介, 2008/7/25
  33. アートのための数学 牟田 淳 2008/5/20
  34. プログラミングErlang Joe Armstrong, 榊原一矢, 2008/2/22
  35. アジャイルプラクティス 達人プログラマに学ぶ現場開発者の習慣 Venkat Subramaniam, Andy Hunt, 木下 史彦, 角谷 信太郎, 2007/12/21,
  36. RailsによるアジャイルWebアプリケーション開発 第2版 Dave Thomas, David Heinemeier Hansson ,前田 修吾, 2007/10/25
  37. アジャイルレトロスペクティブズ 強いチームを育てる「ふりかえり」の手引き Esther Derby, Diana Larsen, 角 征典, 2007/9/25
  38. 基礎からわかるTCP/IP―ネットワークコンピューティング入門 第2版(村山 公保) 2007/8/23
  39. Subversion実践入門:達人プログラマに学ぶバージョン管理(第2版) Mike Mason, でびあんぐる, 2007/4/20
  40. マスタリングTCP/IP 入門編 第4版 竹下 隆史, 村山 公保, 荒井 透, 苅田 幸雄 2007/2/23
  41. マスタリングTCP/IP ルーティング編 山川 秀人, 水谷 昭博, 亀野 英孝, 森 明治 2007/2/23
  42. My Job Went To India オフショア時代のソフトウェア開発者サバイバルガイド Chad Fowler, でびあんぐる, 2006/9/25
  43. Ship It! ソフトウェアプロジェクト 成功のための達人式ガイドブック Jared Richardson, William Gwaltney Jr., でびあんぐる, 2006/8/24
  44. Building Secure Software―ソフトウェアセキュリティについて開発者が知っているべきこと John Viega, Gary McGraw, 齋藤 孝道, 2006/7/21
  45. マスタリングTCP/IP IPsec編 谷口 功, 水澤 紀子 2006/5/23
  46. RailsによるアジャイルWebアプリケーション開発前田 修吾, 2006/2/24
  47. Joel on Software Joel Spolsky, 青木 靖, 2005/12/20
  48. Excelで学ぶ株式投資―Excelで実践する、銘柄の選び方からテクニカル分析の基本、シミュレーション(バックテスト)まで 2005/10/18
  49. マスタリングTCP/IP SNMP編 緒方 亮, 矢野 ミチル, 鈴木 暢 2005/9/21
  50. ネットワークの考え方―ルータとスイッチは何が違う?戸根 勤2005/6/14
  51. ITRONプログラミング入門―H8マイコンとHOSで始める組み込み開発 濱原 和明 2005/4/22
  52. マスタリングTCP/IP IPv6編 IRIユビキタス研究所 2005/2/10
  53. プログラミングのための線形代数 平岡 和幸, 堀 玄 2004/10/25
  54. OpenSSL―暗号・PKI・SSL/TLSライブラリの詳細― John Viega, Matt Messier, Pravir Chandra, 齋藤 孝道,) 2004/8/20
  55. BGP―TCP/IPルーティングとオペレーションの実際 Iljitsch van Beijnum, 近藤 邦昭, 2004/7/23
  56. マスタリングTCP/IP RTP編 Colin Perkins, 小川 晃通, 2004/4/20
  57. スティーリング・ザ・ネットワーク―いかにしてネットワークは侵入されるか Ryan Russell, Dan "Effugas" Kaminsky, Joe Grand, Mark Burnett, Paul Craig, 増田 智一 2004/3/25
  58. 基礎からわかるTCP/IP SIPによるVoIPプログラミング―Linux対応 マッキーソフト 2004/3/19
  59. マスタリングTCP/IP SSL/TLS編 Eric Rescorla,齋藤 孝道, 古森 貞, 鬼頭 利之 2003/11/27
  60. 基礎から学ぶ Webデータベースプログラミング 2003/9/22
  61. マスタリングTCP/IP ネットワークデザイン編 Tony Kenyon, 苅田 幸雄 2003/9/19
  62. TCP/IPソケットプログラミング Java編 Kenneth L. Calvert, Michael J. Donahoo, 小高 知宏, 2003/5/23
  63. TCP/IPソケットプログラミング C言語編 Michael J. Donahoo, Kenneth L. Calvert, 小高 知宏, 2003/5/23
  64. 基礎から学ぶ PerlによるWebサイト管理 John Callender, 湊 規生, 森 弘之2003/5/22
  65. 基礎から学ぶ PerlによるWebプログラミング John Callender, 湊 規生, ソシオメディア 2003/4/24
  66. 基礎から学ぶ CGIプログラミング渡辺 恭成2003/2/24
  67. マスタリングTCP/IP SIP編 Henry Sinnreich, Alan B. Johnston , 株式会社ソフトフロント, 2002/10/23
  68. Excelで学ぶテキストマイニング入門林 俊克 2002/10/22
  69. Ruby Magic ― Rubyで極める正規表現竹内 仁2002/9/24

企画制作についてのふりかえり

前に勤めていた会社がなくなって、「マスタリングTCP/IPみたいな本を作ってる人がいる会社なら大丈夫だろう」くらいの感覚で応募書類を送ったのが2001年。 ちなみに当時のマスタリングTCP/IPシリーズは、「入門編 第2版」と「応用編」、それになぜか「マルチキャスト編」というラインナップでした。

入社試験で「本の企画を書け」と言われた気がした(のちに誤解だったと判明)ので、『マスタリングMPLS』という本の企画書をでっちあげて提出したところ、たまたま当時の開発部で『マスタリングTCP/IP MPLS編』の新刊制作が進行中というタイミングだったらしく、そんな縁もあって「マスタリングTCP/IP」の企画制作をやっていた「開発部」に配属されました。その後は、ずっと開発部で本を作ってきました。

入社後すぐに企画したのはSIPの解説書でした。 ちょうどVoIPとかIP QoS制御とかをキャリア網でも本気でやろうっていう機運があったころで、SIP解説書の企画とかぜったいあるだろうと思ってたのですが、社内の誰もSIPすら知らないという真空状態だったので、自分でやることになったのです。 いま思い返すと、この本(『マスタリングTCP/IP SIP編』)の企画制作をとおして、「需要がありそうな技術の解説書を計画し、適切な著者や監修者を探して、制作して売る」という商売の基本的な流れを学んだ気がします。 幸いにして、とてもたくさんの方に読んでもらいました。

最初の年は、平行して半持ち込み企画もいくつか担当しました。 なかでも『Excelで学ぶ テキストマイニング入門』と『Ruby Magic Rubyで極める正規表現』は、かなり手を入れた思い出があります。 特に後者は、自分がRubyを学ぶきっかけになりました(それまではPerlを使っていた)。

こうして振り返ると、「マスタリングTCP/IP」シリーズの担当者みたいな立ち位置が固まってきたのは入社2年目の2003年だったようです。 当時のシリーズは、自分の入社時にちょうど第3版が出版された「入門編」こそメンテが続いていたものの、おなじタイミングで出版された「MPLS編」のほうはあまり芳しくありませんでした。 そんな中で、「SIP編」の成功をきっかけに、なんとなく自分がテコ入れをはじめることになったのだと思います。

手始めに着手したのは、なぜか日本語の解説書がなかったプロトコルの「SSL/TLS編」と「RTP編」でした (『マスタリングTCP/IP RTP編』は、書籍そのもの以上に、あきみちさんとはじめて仕事できたという意味で自分にとっては大きな出来事でした)。 さらに、もうちょっと低レイヤの解説も欲しいよねということで「ネットワークデザイン編」を企画。 マスタリングTCP/IPという枠ではフォローできてなかったソケットプログラミングの入門書も企画しました。

余談ですが、このころは外部のプロダクションに依頼して普通にDTPで本を作ってもらっていました。 でも、著者校でどうしても入る修正による手戻りの絶望的な困難さを回避したくて、「SSL/TLS編」と「RTP編」では自分で原稿をHTML化してCSSでゼロ校を作り、それを最初の著者校にするという進行を導入していました。 このへんの経験は、後年、XML版管理+LaTeXによる自動組版で生きてきます。

この入社2年目には企画の失敗も経験しました。 Web周りの入門書も必要だよね、という素朴な発想で、CGIとかサイト管理の入門書も何冊か企画したのですが、どれもあまり成功しませんでした。 あまりほめられた話ではないかもだけど、これらを通して「技術書の企画に失敗する方法」を学べたと自覚しています(この年以降で赤字に終わった企画は1冊だけです。えへん)。

翌2004年は、いまになって思うと、このあと数年間の技術書企画制作者としての道を決定づける仕事ばかりだった一年でした。 なんといっても大きいのは『プログラミングのための線形代数』で、この本の企画制作では著者の二人から本当にたくさんのことを学びました。 「コンピュータ書のように読める数学の教科書が作りたい」という恥ずかしいほど素朴な思い付きだけで平岡さんに話を持ちこんだら鳥肌が立つような原稿が書きあがってきたのは、今思い返しても興奮する体験です。 LaTeXで本を作ったのも、轟木さんにカバーをお願いしたのも、原稿の版管理(CVSだけど)を始めたのも、この本が最初でした。

メイン企画者ではないのだけど、『マンガでわかる統計学』の企画立ち上げや技術レビューにかかわったのも2004年でした。

2005年は、引き続きマスタリングTCP/IPシリーズの拡充や、『Joel on Software』とか『ITRONプログラミング入門』といった自分にとって名刺代わりになるラインナップを少しずつ増やしていった年だったようです。

2006年は、XML原稿からのLaTeXによる自動組版で売り物になる本を作った最初の年でした。それが『RailsによるアジャイルWebアプリケーション開発』です。 この本の原著出版社であるPragProg社では、独自のXMLを原稿の形式にしていて、これを翻訳版でもそのまま最大限に使ってやろうと思って正月にGaucheでLaTeXへのコンバータを書いたのでした。 同じ年の『Ship It!』と『My Job Went To India』も、やはりPragProg社の本の翻訳だったので、このときの仕組みをそっくり流用して制作しました。

でも、この年でいちばん学ぶところが大きかった本は『Building Secure Software』でしょう。 自分の企画でもっとも大きな赤字を出した本です。 この本からは、内容の良さと利益はまったく相関しないんだという事実を思い知りました。

翌2007年あたりから、だんだん、作りたい本を作りたい形に作れるようになってきた気がします。 2008年の『実践Common Lisp』と『プログラミングErlang』のように、爆発的には売れないけど意義があったりブランドにつながったりする本(しかも着実に利益が出る本)を企画できるようになってきました。 2007年末のオブジェクト倶楽部のイベントで自分たちの本の作り方をプレゼンする機会があったり(登壇したのは同じチームの高尾さん。スライドは自分が作った)、 Gauche Night 2008で発表したり、アジャイル界隈の方々やLisp界隈の方々に少しずつ自分たちチームの存在を認知してもらい始めたころです。

2009年には、企画構想から長いことかかった『プログラミングのための確率統計』がついに形になったり、趣味で読んでた"Programming Haskell"が翻訳企画になったり、自分たちの制作環境でSubversionからの移行を始めていたGitの解説書を出せたり、いろいろタイミングが良かった年でした。 発行はこの翌年になる『内科診療ヒントブック』の話を、ブログの一読者として一方的に知っていたmedtoolzさんからいただいたのも、この年のことです。 『Scheme手習い』とか『関数プログラミングの楽しみ』とかを通して、価値があると信じる本だけで商売ができるし、そうすべきなんだなという実感を強めました。

2010年以降も、マスタリングTCP/IPシリーズのメンテと拡充を続けながら、"The Little Schemer"の翻訳とか、『インターネットのカタチ』、『すごいHaskell』、TAPLの翻訳、Bird先生の関数プログラミング本の翻訳、あのカーニハン先生の著書などなど、ものすごい経歴の著者訳者の方々と一緒に、内容も責任も重い、でも楽しい仕事をたくさんしてきました。 それまで手探り状態でがんばっていた自動組版化も、良い意味でルーチン化でき、効率よくチームで仕事を回せていたと思います。 最後の数年は、自分たちのチーム以外の企画も技術面でサポートできる余裕もでき、開発部全体でよい仕事ができていたと思います。