PureBuilder のちょっといいトコ

この記事は事前生成戦略/PureBuilderに関する論文を一般向けにわかりやすくまとめ、補足したものです。

内容としては高度に技術的な記事となっております。

事前生成戦略のおこり

もともと私が事前生成戦略について研究し始めたのは2000年のことでした。

当時はPerlを使ったCGIアプリケーションが人気で、これを共有スペースのレンタルサーバーで動かす(主に掲示板、カウンター、そしてチャットを)のが定番でした。

そして、こうしたレンタルサーバーではリソースを使う、あるいは応答までに時間がかかるアプリケーションは厳しいペナルティが課されるようになっていました。

当時のチャットで定番だったのはゆいちゃっとで、現在は廃れたフレームを使った構造でした。

まず思ったのは発言を入力する部分はアプリケーションで生成しなくてもよいのではないか?ということです。 ゆいちゃっとの使用しては入力部分に名前などがあるため生成しなければならない部分はありますが、果たしてそれは発言欄に入れなければならないものでしょうか。

こうして「できる限りアプリケーションを限定していく」という方針が生まれました。

また、2ちゃんねるの8月危機を機に、私は「必要ない」と否定されたHTMLの静的生成の可能性を支持していました。 もちろん、プログラムで書くのならなんでもできますが、基本的に大型の熟成されたプログラムは優秀であり、自身で開発し保守していくよりも良い結果が期待できます。 であれば、できるだけApacheに組み込まれている標準機能に頼る方が解決は楽なのではないか、と考えたわけです。

当時はレンタルサーバーですから、Apacheを制御する権限がなく、それに代わる方法としてCGIアプリケーションで面倒を見ることもできました。 しかし、今後の発展を考えればそれは望ましくない、と考えたわけです。

では静的生成はどれくらいの効果があるのでしょうか?

チャットの場合、当時はページを読み直さなければ発言を取得できない構造でした。 このリロード行為ですが、およそ15秒から30秒おきに設定されているのが一般的です。

ですが、実際にはユーザーはリロードを連打するのが当たり前になっていました。 そのためチャットは非常に負荷が高く、CGIの利用はできるにもかかわらずチャットアプリケーションを禁止しているサービスもありました。

発言間隔は速い人でも20秒はあきますし、だいたい1分1回が目安です。 ルームに10人いるとすると、30分で発言する回数は30回、読み込まれる回数は720回ほどです。

これだけ差があるのであれば、書き込んだときだけHTMLを生成し、表示は単にHTMLを表示するだけ、としました。 これでフレームで表示される発言欄、チャット欄ともに静的HTMLとなり、発言欄でのフォーム送信先だけがCGIアプリケーションとなっている形です。

付加的動的要素はJavaScriptで実現していました。 この時点で「JavaScriptは付加的コンテンツに限り必須としない」という形式が取られていました。

このチャットシステムは2003年から私のウェブサイトで実験的に導入されました。

また、2005年には「ウェブサイトの共通部分を各HTMLに書かない」「目次を自動的に作る」といった目的でACCS (ACCS1) を制作し、使っていました。

事前生成戦略のメリット

速度

最大のメリットは速度です。

静的なHTMLファイルが使われる機会は減っているにもかかわらず、ウェブサーバーが静的なページを応答する速度は飛躍的に向上しました。 Lighttpdもなかなかの速度でしたが、Nginxは非常に高速です。

構造的に「静的なファイルを返す」というのは「なにも返さない」に次いで速く、いかなるウェブアプリケーションを用いるよりも高速です。

「オンメモリデータベースを使えば速い」といった意見もありますが、オンメモリファイルシステムを使えばさらに高速化できます。

もちろん設計上も無駄なリダイレクトを介したり、サーバーリレーを行わない前提です。

ステップ数が減ればそれだけ速くなりますし、静的なファイルを返すのはアプリケーションにさらなる処理を行わせるよりも高速です。

最近はCDNを使う方法がより高速ですが、それは静的なファイルをより高速に配信する方法であり、 静的なファイルにすることが最大な高速化となるのは間違いありません。

取り回しの良さ

各アプリケーションにHTTP関連の機能を盛り込まなくてもサーバーの設定で済ませることができ、 HTTPの新しい仕様もwebサーバー任せにできます。

自力で実装するよりも品質が高く保たれる可能性が高いでしょう。

ハードルを下げられる

「静的なファイルを配置できるウェブサーバー」という要件は極めて低く、 無料のスペースなどを使いたい場合にはかなり大きなアドバンテージになります。

例えばPureBuilder Simplyで生成したページをGitHub Pagesに配置することも可能です。 GitHub PagesでWebテンプレートを使うという方法はPelicanが使われることが多いようです。 これはやむなく静的に生成するという方法ですが、同様のアプローチではあります。

PureBuilderの利点については後述します。

また、動的に生成せざるを得ない部分についても分離し、最小に分けることができます。

応答性

チャット、あるいはWordPressのようなアプリケーションは送信が完了し、アプリケーションが処理を完了するまで応答を保留します。 つまりユーザーが操作してからページが表示されるまでとても時間がかかります。WordPressでは数分待たされることすらもあります。

快適なアプリケーションを作ろうとすると、いかに速く処理するかという問題が出てきますが、どうしてもそれは限度があります。

事前生成することによりユーザーのリクエストに対しては即座に返すことができます。 そのため、生成に時間がかかったとしてもあまり問題はありません。チャットのように「なるべく速くしたいもの」を優先的に、「すぐではないけれどいずれ必要となるもの」を余ったときにやれば良いわけです。

この仕組みは静的HTMLという枠を越えて適用可能です。 WordPressのキャッシュ機構も最初にアクセスされたときに生成します。 生成されるタイミングは記事が投稿されたときだけでなく、コメントがついたとき、記事が追加されたとき、ウィジットが編集されたときなど多く、結構な頻度でユーザーは遅いアクセスを繰り返すことになります。 (まぁ、botが早々に揃って生成してくれたりもしますが)

ページが生成可能な状態になったとき、いつまでに生成すればユーザーのファーストアクセスに先んじることができるか? というのは結構難しい問題で、このテクニックは現在のAI開発にも応用しています。 しかし、ファーストアクセスが先になった場合には待たせてでも生成するようにしてしまえば「間に合わない」ことは致命的な問題ではないため、 「アクセスが予測される計算が必要なデータをアクセスより前に計算する」という戦略は応答性を確実に向上させます。

事前生成戦略の適用範囲

アクセスが予測可能なものでかつ集中型ならばなんにでも、です。

更新頻度の高いチャットでも事前生成戦略によって非常に快適な状態に改善することができることを確認しています。

適さないのは予測できないもの、ユーザーごとに表示内容がそもそも異なるものです。

予測できないものの典型例は検索で、既に検索されたものはまた検索されるのではないか、と考えられますが、 検索の事前生成をキャッシュより意味のあるものにすることは困難です。

また部分的な違いはJavaScriptなどによって吸収することもできますが、TwitterやFacebookのような表示すべき内容がユーザーごとに異なり、ユーザーがそれを見ない可能性も高いものは事前生成すべきではありません。

PureBuilder Simplyのデザイン

シリーズの中でのPureBuilder Simply

サイトビルダーとしてはACCSシリーズ、PureBuilderシリーズに続く登場となったPureBuilder Simply。 PureBuilderの名を関してからは3番目のソフトウェアとなりますが、それぞれ特徴があります。

PureBuilderは基本的にZshスクリプトで書かれていました。 Unixライクなプラットフォーム専用であり、ウェブサイトを構築するための変換作業をZshスクリプトに書くという形です。

しかし構築の違いは設定ファイルという名のZshスクリプトに書くことになり、 その拡張もZshで行うことになります。 事実上フレームワークのような存在で、個人的には使いやすかったものの、サービスとして提供するには難易度が高すぎる(ユーザーがメンテナンスできるようなものではない)という点が問題でした。

PureBuilder 2はサービスとして提供しやすいよう、Windowsでも動作するRubyで書かれたソフトウェアになりました。 制御も設定ファイルで行えるようになり、汎用性が増しました。 また、PureBuilderは文書は「PureDocまたはPureDoc 2で書く」という仕様でしたが、いずれも専用のフォーマットになってしまいます。 PureBuilder 2ではPureDoc (Zshベース)のサポートをやめ、PureDoc2 (Rubyベース)またはMarkdown (Kramdown)という汎用性のあるフォーマットを利用可能としました。

これはある程度満足できるソフトウェアでしたが、割と複雑で、設置と設定が難しいものでした。 ユーザーが使いにくい、というのもありますし、設置するにしてもコンテンツを増やすにしても割と面倒で、Mimir Yokohamaのサービスとしては採算の取れない手間のかかるものでもありました。

PureBuiler Simplyは大胆に仕様を変更しました。 「ドキュメントの生成そのものはPandocに任せる」というものです。

Pandocは極めて優秀なソフトウェアであり、PandocのMarkdownは極めて豊富な機能を持ちます。 そのため、単純にテンプレートを適用する部分ではよりシンプルなPandocの機能を使うことができるようになり、 プログラミング言語の一部をなすために「文書がバグっている」という事態を発生しやすいPureDocのサポートをやめてしまうことができました (現在はPureDocそのものがdiscontinuedになっています)。

文書への対応もPandocに任せることができるようになり、機能性も向上しました。 現在はPandoc MarkdownまたはReSTructured Textに対応しています。

ドキュメント生成系の機能がなくなったためコンパクトになったPureBuilder Simplyですが、 仕組みが整頓されたため非常にわかりやすく、快適になりました。

設置も用意で維持もしやすく、少し技術力があればユーザーでのカスタマイズも難しくありません。

デザイン概略

実はPureBuilder Simplyのデビュー戦はこのMimir Yokohamaのウェブサイトです。

Mimir Yokohamaのウェブサイトは当初、突貫で作ったためWordPressだったのですが、使っていたWordPressサーバーが応答が極めて長くなるというトラブルに見舞われました。 これに対応するため、新しいウェブサイトを構築することを目的として1ヶ月で作られたのがPureBuilder Simplyです。

第一の目標は当時現行だったWordPress版を再現することでした。 新しいウェブサイトでは従来のHTMLやCSSは全く使用されていませんが、移行したことには気づかなかった方のほうが多いことでしょう。 JavaScriptを使わないハンバーガーメニューなども投入し、違和感ないようにしました。

Mimir Yokohamaはそれ以降PureBuilder Simplyのショーケースを兼ねて拡張が続けられています。 しかし、実はPureBuilder Simply本体はあまり変更が加えられていません。 以下はコミットログから抽出したコミットの日付です。

Date:   Sun Jul 22 23:03:38 2018 +0900
Date:   Fri Jul 20 22:38:28 2018 +0900
Date:   Mon Jul 9 20:21:20 2018 +0900
Date:   Sun Jul 8 00:23:57 2018 +0900
Date:   Tue May 22 01:58:36 2018 +0900
Date:   Sun May 20 20:55:54 2018 +0900
Date:   Wed Feb 21 21:40:06 2018 +0900
Date:   Thu Feb 8 00:15:52 2018 +0900
Date:   Fri Dec 22 23:27:22 2017 +0900
Date:   Fri Dec 15 12:12:37 2017 +0900
Date:   Fri Dec 15 03:57:00 2017 +0900

近い日付のコミットは一連の作業、あるいはその変更によって新しく出現したバグの修正だと言えますから、改善や拡張を行ったのはわずか3回ということになります。

PureBuilder Simply自体の修正はわずか3回にとどまるにもかかわらず、Mimir Yokohamaの相次ぐ拡張をPureBuilder Simplyの枠組みで実現できていることは、PureBuilder Simplyが極めて柔軟性・拡張性に富むことを示しています。

実際、Pandocを使う場合書けるものは対応したドキュメントだけですから、動的要素の入れようがありません。 しかしPandocが受け付ける範囲で柔軟に扱えるようPureBuilder Simplyで面倒を見るように拡張しており1、それでは不足な部分については、テンプレートを加工するeRuby Extend2, ドキュメントを加工するpre-plugins, 生成したHTMLファイルを加工するpost-pluginsの3つによってプログラムによって生成するのと変わらないレベルの自由度を得られています。

PureBuilder Simplyにとって最も大きな成功は、「文書のメタデータを読み取ってデータベース化し、シリアライズする」という仕組みにあると思います。 PureBuilder Simplyは従来と違い、文書そのものを読み取ったり、書き換えたりすることは一切しません。 しかし、メタデータだけは読むようにしています。 幸いにもMarkdownのメタデータはYAMLで書かれています。

このことからインデックスページのような「ページの本文ではなく情報使うページ」の生成がPureBuilder Simplyに頼らずとも可能になりました。 従来は極めて複雑な処理をしていた「前後ページの設定」も非常に楽になりました。

PureBuilderの挙動を詳細に解説することは避けますが、「文書のメタデータを読んでPandocに渡す、生成が終わったらメタデータをデータベースに保存する」というのが基本的な動作です。 post-pluginsは生成ごとではなく、すべての生成が終わったあと各生成したドキュメントに対して行います。


  1. 主にYAML front matterについて非標準のものを積極的に受け入れ、またPureBuilder Simply側でも理解するようにしています。

  2. この機能は動作が複雑になるため、Mimir Yokohamaではこの機能を使わずにサイトを構築することにこだわっています。