技術書典5 で『マスタリング docutils』を出版しました

先週末、技術書典5に「マークアップ言語愛好会」というサークルで参加し、『マスタリング docutils』という本を出版しました。
techbookfest.org
techbookfest.org

マスタリング docutils

この本はこんなまえがきからはじまります。

みなさんは docutils をご存知でしょうか。
docutils はふたつの側面を持つソフトウェアです。
ひとつは Python 製のドキュメント処理フレームワークとしての側面。
もうひとつはそのフレームワークの上に実装されたドキュメント変換ツール群としての側面です。


本書では、前者のドキュメント処理フレームワークとしての docutils にスポットを当て、どのような構造をしているのか、
どのような順序で処理が行われるのか、そしてどのように拡張するのかについて紹介します。

Sphinx はこの docutils の上に構築されたツールです。したがって、SphinxSphinx 拡張を作る上で避けては通れません。しかし、残念なことに docutils はドキュメントや解説が少なく、理解がとてもむずかしいという問題があります。
自分が Sphinx の拡張を書き始めたときに、最初につまづいた (そして今も時々つまづく) のがここです。

本書はその問題をカバーすべく、docutils がどのような構造をしているのか、どのようなフローで処理が進むのか、
そしてどこが拡張ポイントなのかというのを紹介したおそらく世界初の docutils 解説書です。

執筆から販売まで

申し込んだ時点から予想はしていたのですが、今回は執筆時間に充てる時間が限られていました。
9月半ばに開催された PyCon JP 2018 での発表資料づくりに手間取ってしまったため、執筆できるようになったのが 2週間前でした。
そこからハイペースに執筆をして仕上げたのが本書です。

執筆期間が短いとボリュームが…という懸念があったものの書き上げてみると 60ページ弱になりましたし、
肝心のクオリティについても、(断腸の思いで一部見送った章があるものの) おおよそまんぞく行くものができました。

普段からよく触って中も覗いている docutils ですが、今回の執筆にあたって改めてこんなことをしています。

  • 歴史を追うために Doc-SIG の投稿を(ピックアップしながら)斜め読みした
  • 経緯を知るために PEP 256-258 をひたすら読んだ
  • 説明のために docutils のコードを読みふけった

ですので、内容についても胸を張ってお見せできるものです。

ひとつ残念だったのは、ギリギリすぎるスケジュールによって印刷に回す時間が取れなかったことですね。
そもそも技術書典に申し込んだゴールのひとつが Sphinx を使って、執筆から出版(印刷)までの過程を体感してみるというものだったので、自分の目標としては未達成でした。残念。

ツール

今回執筆に使ったのはこのあたりのツール / サービスです。

  • Sphinx (執筆、出力)
  • gitlab (CI)
  • Google drawings (画像)
  • slack (オンラインレビュー / 監視)
  • ラクスル (ダウンロードカード印刷)
  • ジョナサン (セルフ缶詰スペース)

反省

Twitter でいろいろ書いたのを貼り付けておきます。









今後の予定

本書をほしいという奇特な方が現れたので、Booth でダウンロード販売をしています。
興味がある方はこちらからどうぞ。

また、ダウンロードカードはまだ余っているので、カードが欲しい人はお声がけください。

大事なこと

本書で docutils に興味を持った人は、実際に docutils フレームワークをフル活用している事例として Sphinx があるので、
ぜひとも一緒に開発しませんか!
Sphinx プロジェクトではいつでも協力者を求めていますよ!

Re: Sphinx コードの半減期と未来予想図

ぼちぼち Sphinx-1.8 をリリースしようというこのタイミングで、以前書いた Sphinx コードの半減期と未来予想図 - Hack like a rolling stone を見かけたので、1年半ぶりに試してみました。

将来、また実行したくなったときにさくっと再現できるようにこんな Dockerfile を書きました。全部 RUN で書いてるのでとても雑ですね。

FROM ubuntu:bionic

RUN apt update; apt install -y python3 python3-pip git; apt-get clean
RUN pip3 install git-of-theseus
RUN git clone https://github.com/sphinx-doc/sphinx /sphinx
RUN git-of-theseus-analyze --ignore 'tests/*' /sphinx
RUN git-of-theseus-stack-plot /cohorts.json
RUN git-of-theseus-survival-plot /survival.json
RUN for mod in application builders directives domains environment ext util writers; \
do (cd /sphinx; echo $mod; find sphinx/$mod* -type f -exec git annotate {} \; | perl -ne 'm/(\d+)-\d+-\d+/; print $1, "\n"' | sort | uniq -c; echo); \
done
CMD cp /*.png /mnt

現時点の半減期グラフはこうなりました。なお、今回は tests/ ディレクトリは対象外にしています。
f:id:tk0miya:20180826183051p:plain

徐々にコード規模が増えてきてますね。
5年以上前のコードも徐々に新しいコードに入れ替わっていっています。2010-2012 あたりのコードは完全に虫の息ですね。


もうひとつのグラフは主要モジュールごとの年代比率です。
f:id:tk0miya:20180826164448p:plain
どのモジュールもここ 3年で大きく手が入っていますね。environment などは 75% 以上の書き換えが行われています。
これは行ごとのタイムスタンプから計算しているので、実装が大幅に変わったかどうかはわかりません (typo 修正にも反応する)が、リリースから 10年が経過したいまでもあちこちに手が入っていることがわかります。

ext や writers あたりは比較的古いコードがそのまま残されているようです。
この傾向は自分の感覚とも一致しています。


ところで、以前の記事ではこんなゴールを挙げていました。

  • Sphinx を細かくモジュール分割すること
  • モジュールの結合度を下げること
  • Sphinx 自身を Sphinx API で作ること

自分の感触としては、まだ道半ばという感じです。
クラス変数を使う箇所をかなり削ったり、API やモジュールの責務を整理したりと、一歩ずつ前に進んでいるので引き続き頑張っていきたいところです。

Sphinx 開発進捗報告 (2018.8)

みなさん、お久しぶりです。tk0miya です。

大変多くの方にスポンサーをしていただいたこともあって(参考)、なるべく定期的に進捗を報告したいなと思っていたのですが、ワールドカップを見ている間に今年もあっという間に半分以上過ぎてしまいました。時間が経つのは早いですね。

というわけで、Sphinx の開発進捗報告です。
f:id:tk0miya:20180804194048p:plain
イシューと PR の残数はこんな感じで遷移しています。
多少ジグザグしているものの、今年に入ってからおおよそ右肩上がりで推移していることがわかるかと思います。

片付けた件数はそれぞれイシューが 415件、PR が 526件でした。
それなりにクローズしているのですが、新たに投稿されるものがそれなりにあるということですね。

ちなみに、Sphinx プロジェクトでは久しぶりに新しいメンバーを迎えました。
検索やドキュメントまわりを担当してくれる TimKam です。
僕が不得意な JavaScript まわりをテコ入れしてくれるようなので、非常に期待しています。

さて、Sphinx は 9月にバージョン 1.8 のリリースを予定しています。
続いて来年の春にはいよいよ 2.0 がやってきます。
もともとは定期的なリリースのひとつでしかなかったのですが、古い API の削除や Python 2.7 のサポート終了など、いくつか大きい変更も行われます。

Enjoy documentation!

blockdiag を github に移動しました。

blockdiag の開発拠点を bitbucket から github に移動しました。

開発を始めた 2011年ごろ、僕は git より mercurial を好んでいたので bitbucket をメインリポジトリとしてチョイスしたのですが、
CI などを含めた周辺サービスとして、github に破れた感が長引いていました。drone.io も止まっていましたしね。

長らく更新すらしていなかったので、完全に見て見ぬふりをしていたのですが、新たにバグが報告されたのを受けて
重い腰を上げて github に移行することにしました。

イシューの移動

ソースコードそのものは、github の import 機能がいい感じにやってくれるので、何も考える必要はありません。
しかし、イシューについてはそうもいきません。

そこで @shimizukawa さんが改造した bitbucket_issue_migrator を使います。
www.freia.jp

ただ、この記事にも書いてありますが、そのまま利用すると全ての移行イシューの投稿者が自分になってしまいます。
その例として、Sphinx では先頭 2000件ぐらいのイシューは @shimizukawa アイコンが表示されています。

今回はその轍を踏まないようにアカウントを作ろうとしたのですが、残念ながら失敗に終わりました。
github の規約上、1人につき free account は1件までという規約があるそうで、それに引っかかってしまいました*1
というわけで、移行したイシューはすべて自分がオーナーになってます。

使い方は記事を見てください。

PR の移行

ツールが見当たらなかったこともあって、早々に諦めました。

CI 他の設定

まだやっていません。

今後の見通し

github に移動したことを受けてちょこちょこ進めていこうかと思っています。
ただ、Sphinx に割く時間がメインなのはしばらく変わらないと思います。
開発をぐいぐいと進めたいと思ってる人は、PR を投げるなりメンテナに立候補するなりしてください。

*1:知らずにトライしてしまい、サポートの方に余計な手間を掛けさせてしまいました。申し訳ない。

僕自身のスポンサーシップをはじめました

タイトルのとおりです。僕を支援していただくためのスポンサーシップをはじめました。

おかげさまでとても多くの方に賛同していただき、かなりの額を支援していただきました。
Sphinx やら blockdiag やら、自分が関わっているプロダクトが多くの人に使われている結果なのだと思うと、これからも継続していこうと思いを新たにしました。

ここでは、スポンサーシップを初めたときの自分の考えをまとめておこうかと思います。

なぜはじめたのか

gist にも書いたように、お茶代の捻出が目的です。
Sphinx のメンテナをやるようになってから、ちょくちょく喫茶店で開発をするようになりました。
通勤の電車の中や自宅でも活動しいますが、休日はまとまった時間を使うために近所の喫茶店にこもることが多々あります。
集中しやすいとか、気分転換とか、いくつかの要素があるんじゃないかと思っています。

ありがたいことに僕の OSS 活動にはあまり費用が掛かっていません。
最近は GitHubTravis CI のように、いろんなサービスで OSS 向けに無料のサービス提供をしていますし、所属している会社(株式会社タイムインターメディア)が開発機材を貸与してくれています*1。確かにドメインの更新費用やちょっとしたサービス利用料(S3 やら DNS やら)があるにはあるのですが、ちょっとした持ち出しで済んでいました。
そんな低コストの活動の中で、ひとつだけ "それなりの額" が掛かっているのが喫茶店代なのです。

チリも積もれば、とはよく言ったもので、一杯ではたいしたことがない紅茶も、たくさん飲めば結構な額に積み上がるんですね。束で買ったコーヒーチケットが雄弁に語っています。
f:id:tk0miya:20180421151943j:plain

喫茶店で開発してるなんて贅沢してるなー、と自分でも思う部分があるのですが、開発がはかどっているのも実感としてあります。そこで、この費用を個人の持ち出しではなく、スポンサーという形で協力してもらえないかと今回呼びかけてみました。

なぜ個人へのスポンサーなのか

今回募集しているスポンサーシップは、個人に対するものです。
Sphinx プロジェクトや blockdiag プロジェクトで呼びかけているものではありません。

理想で言えば、Sphinx プロジェクトとして広く (海外からも) 支援を受けたほうが、金額も集まりやすいですし、より多くの開発者に還元することができそうです。では、なぜ今回はプロジェクトとしてのスポンサーシップにしなかったのでしょうか。理由はふたつあります。

ひとつは先ほど説明したように、そもそものモチベーションがお茶代の支援という、極めて個人的で、しかも目標額が低いものだったのもあり、プロジェクトとして呼びかけるのは仰々しすぎました。

もうひとつは分配の問題です。現在の Sphinx プロジェクトはかなり多くの部分を僕がカバーしているとは言え、他のメンテナも要所要所で手助けしてくれているのも確かです。プロジェクトとしてスポンサーを集めた場合は、彼らにも同様に支援がなされるべきです。それを考えると一気に事務コストが増えます。公平な分配とはなんなのか。予算管理が必要になるのではないか。また、国際送金や税金についても考えなくてはなりません。

こうしたことを考えたときに、プロジェクトとしてスポンサーシップを進めるのはあまりに手間がかかりすぎると考えたので、こちらの線で検討するのは早々に諦めました。こうした分野に知見がある方が手伝ってくれるのであれば、いつかはプロジェクト規模でできると良いですが、今はその時ではないと考えています (自分の可処分時間を考えても)。

OSS でお金をもらうことについて

正直なところ、自分が OSS でお金をいただくことについては、自分の中でもスッキリはしていません。
自分ではない誰かが対価を得ることや、寄付を受けることについては気にならないのですが、いざ自分になると…という謎の感情があります。

あまり意識をしたことはないのですが、自分の中では OSS 活動は奉仕活動に近い、無償の活動だという思い込みがあるのかもしれません。一方で、それぞれの開発者のリソースは有限ですから、その活動は何かしらの形で讃えられてもおかしくないし、OSS でうまく稼げるのであればそれはそれでよい、とする見方も同居しています。
他者に対しては継続的でよいやり方だ、と褒め称える一方で、自分の場合はその部分にブレーキを踏んでいるのかもしれません。正直、自分でもなんでそんな考え方になっているのか、うまく説明できません。

もしかすると、対価を得てしまうと責任が発生するのではないかと恐れているのかもしれませんね。

最終的には半年以上悩んで、はじめて見ることにしました*2

責任感

ということで、責任感はあります。
プロジェクトへの支援であればまだしも、僕個人への支援ですので、もし1年間遊び呆けてしまったら、スポンサーに向けて顔向けできない、というプレッシャーはあります。
急に仕事が忙しくなってしまったら、Sphinx の開発に飽きてしまったらどうしよう、みたいな考えも頭によぎります。

とはいえ、そんなことを心配し続けても仕方がありませんし、そういうぼんやりとした不安はねじ伏せて、前に進むだけです。
いままでも Sphinx のメンテナであることのプレッシャーは多少なりともありましたし、忙しかった時期も遊んでいた時期も含めて、年間通じてメンテナンスし続けていたわけですしね。
お金をもらっていても、もらっていなくても、やることそのものは変わりません。

ということで、顔の皮を厚くしてこれまでのペースで "ほどほどに" やっていこうと思います。
スポンサーシップのおかげで「より速く前に進む」のではなく、これまでのペースを維持するということに捉えて、プレッシャーにしないように意識していこうと思います*3

ちなみに、6月にはワールドカップがあるので、その時期は活動が鈍るのは決定しています。あしからず。

申し訳無さ

つらつらと吐露していくと、他のメンテナ、他の OSS 開発者への申し訳無さみたいなものはあります。
それぞれ自分の時間や、何かしらの費用を持ち出しで OSS への貢献をしているのに、自分だけスポンサードされてよいのか、と思ったりもします。

ここも整理ができていないことのひとつです。なにか思うところがあったら教えてください。

指摘いただいたこと

おっしゃるとおりです。
いまの Sphinx プロジェクトはひとりに作業が偏ってるのであまり健全とは言えません。
過去を振り返っても、作者の Georg が開発していた時期、 @shimizukawa が引き継いで*4メンテナンスしていた時期、そして今、とどの時期もメインのメンテナが作業の大部分をしているというプロジェクトの構造は大きく変わっていません。

ですので、今の時点では協力してもらうべき「他のデベロッパ」がほとんどいないというのがそもそもの問題です。
ドキュメントという地味な分野は人気がないのか、あまり開発に参加したいという人が少ないのです。

ですから、あらためて声を大にしていいます。

Sphinx プロジェクトではメンテナを募集しています。
未経験者歓迎です。

イシューの切り分け、バグの再現確認、ドキュメントの更新、使い方の質問へのフォローアップなどなど、Sphinx の内部構造を知らなくてもできる作業も山ほどあります。
メンテナには日本人が多いので、日本語での相談なども気軽にできます。
興味がある方は声を掛けてもらえるとありがたいです。

税金


そのとおりですね。
寄付額が年間 110万円を超えると贈与税がかかりますので、もし他にスポンサーシップをはじめる人がいたらご注意ください。
自分の場合は問題なさそうです。

まとめ

  • スポンサーシップをはじめました
  • おちこんだりもしたけど、私は元気です
  • スポンサーは引き続き募集中です

*1:いつも言っていますが、非常にありがたいです。感謝しています。

*2:gist の履歴を見ると分かりますね。最初に作ったのは随分前です

*3:そうは言っても、今年に入ってからのペースは結構なものです。スポンサーシップにかかわらずどこかでギアを緩めないと、ふと燃え尽きてしまいそうなのでコントロールしたいところです。

*4:より正確には Georg がフェードアウトしていっただけなので、引き継いではいないようですが…

Sphinx 10周年に寄せて #sphinx10th

本日、Sphinx-1.7.2 をリリースしました。いくつかのバグが修正されているので、試してみてください。
pypi.python.org

さて、リリースするまですっかり忘れていましたが、本日 3月21日は Sphinx の誕生日です。しかも、なんと 10周年です。

Release 0.1.61611 (Mar 21, 2008)
================================

* First public release.

github.com

Sphinx と僕の (だいたい) 10年間

僕が Python を使いはじめた頃から、既に Sphinx はよく使われていたので、かなり古くからあるツールだと思っていたのですが、実は 僕の Python 暦(2010年ごろ)とそんなに変わらないのですね。実際、Python を使いはじめた頃に 0.6.6 を使ってみたり、1.0 のリリースパーティに参加したりした覚えがあって、自分の記憶と CHANGES が一致しています。
sphinx-users.jp

その後、僕は blockdiag シリーズを作り、Sphinx 拡張職人になり、そして Sphinx のメンテナになり…とドキュメンテーションツールに関わり続けてきました。
Python をはじめてから、ずっと Sphinx とその周辺ツールにかかわっていますし、Sphinx を作るために Python を覚えたと言っても過言じゃないかもしれません。
すくなくとも、今では Sphinx が僕のホームであることは間違いありません。
なんとなく Python を使いはじめただけだというのに、なんとも不思議なことです。

この10年、Sphinx は僕の人生を巻き込んで前に進んできました。
毎日英語の読み書きをさせられたり、書籍を書くことになったり、雑誌に寄稿したりと、Sphinx に関わってから僕の生活は一変しました。
Sphinx のおかげで知り合った友人もたくさんいます。Google さんにも表彰されました。
まさか僕が関わっているソフトウェアがあの Debian に収録されていて、さらにカーネルPython、その他諸々のドキュメントを支えているというのは想像もつかなかったことです。

決して派手ではないですが、Sphinx は僕を大きく変えたのです。

10years

10年前はまだ SphinxPython に出会う前で、何者かになりたいというワナビーだった頃です。
10年後のいまは実用的なソフトウェアのメンテナとして活動しています。

もしかすると、夢を叶えてなりたかったものになれたのかもしれません。
もしかすると、適当なところに居着いてしまっただけかもしれません。

かつては自分のやりたいこと、好きなことが選べる可能性を秘めていました。
いまは新しいものに触る時間は取れないし、アイディアがあっても完成させることもなかなかできません。

前に進んだのか、先細ったのか。
そのあたりは僕にもわかりませんが、きっとこの先 10年も Sphinx はそこにあるでしょう。
ソフトウェアがあるかぎり、ドキュメントは必要とされ続けるでしょうから。

あれから10年も。これから10年も。
10年前の自分が今の自分を想像できなかったように、10年後の自分が Sphinx とどう関わっているのかは想像がつきません。
でも、願わくば、なんらかの形で Sphinx と付き合っていけると良いな、と今は思っています。
これからも、きっと Sphinx は前に進んでいることでしょう。来年には Sphinx 2.0 がリリースされる予定です。

次の10年も、Sphinx が多くの開発者の手助けできることを祈って。
おめでとう、Sphinx。ありがとう、Sphinx

#ポエム *1

*1:渡辺美里の 10years を思い出しながら書いていたら、なんだかセンチメンタルでポエミーな記事になってました。あとで恥ずかしくなって転げそうだけど、ぼちぼち日も変わってしまうし、そのまま公開しちゃいます。

Re: Markdownにmetaタグを入れる

つい最近、こんな記事が出ていました。
kamekokamekame.net

いいですね、コミュニティ。さっと拡張を書いてくれる人に優しさを感じます (自画自賛)。

markdown の拡張子は?

さて、この記事では source-read イベントをフックして md_prolog を実現しました。
でも、このコード、よく読むとイベントハンドラで filename.endswith('.md') とか決め打ちしていますね。
これでよいのでしょうか?

適当にぐぐってみると、こんなやりとりが見つかります。
superuser.com
.markdown とか .mkd とか、いろいろ使ってる人がいるんですね。
先ほどのコードは完璧ではありません。

Sphinx における markdown の拡張子

Sphinx では source_parsers の設定で、Markdown パーサを有効にすることが多いですよね*1
source_parsers は conf.py にこんな感じで定義します。

from recommonmark.parser import CommonMarkParser

source_parsers = {
    '.md': CommonMarkParser,
}

source_suffix = ['.rst', '.md']

source_parsers 変数に「拡張子」と「パーサクラス」のペアを列挙します。
そして、source_suffix に対象となる拡張子のリストを並べます。


ここの設定を工夫することで、好みの拡張子を割り当てることができます。

任意の拡張子を考慮した md_prolog

さて、このように Sphinx では任意の拡張子を Markdown 文書として扱うことができます。
これに対して、冒頭の記事で紹介されているコードは対応できていません。
拡張子がハードコードされているため、設定によっては正しく動きません。

これに対応するには次のようなコードを書きます。

from recommonmark.parser import CommonMarkParser

def on_source_read(app, docname, source):
    extensions = tuple([ext in (ext, parser) in app.config.source_parsers.items()
                        if parser is CommonMarkParser])

    filename = app.env.doc2path(docname)
    if filename.endswith(extensions):
        source[0] = app.config.md_prolog + "\n\n" + source[0]

このコードでは source_parsers の値を元に CommonMarkParser が処理する拡張子のファイルかどうかを判定しています。
ちょっとわかりづらいコードになっていますが、これは無事に動くはずです。

いまやほとんどの人は .md を使っているような気もするのですが、つい .markdown を使いたいひとや .mkd 派の貴方はこのコードを使ってみると良いでしょう。

*1:API を使って足すこともできるのですが、recommonmark は使っていません