コンテンツの設計を間違える道は二つあり、たいていのプロジェクトはそのどちらかを選ぶ。一方には「すべてGitに」の原理主義者がいて、彼らにとって誤字を直すことはブランチを切り、プルリクエストを出し、フルデプロイをすることを意味する。他方には、CMSがすべてを——UIの文字列、レイアウトの設定、デザイントークン、そのすべてを——保持すべきだと決める人たちがいて、サイトはネットワーク往復なしにはボタン一つ描画できなくなる。私は自分のポートフォリオとこのブログを同じコンテンツ層の上に作ってきたが、持ちこたえたのは両者のあいだの固い境界だけだった。
最初のうち、私が作るものはすべてリポジトリ内のファイルに——INI、次にJSON——あり、すべてバージョン管理下にあって完全に自分の手の中にあった。それは、そうでなくなるまでは単純だった。スマホから一文を直したい日、あるいはエディタを開かずに考えを公開したい日が来ると、ファイルだけのコンテンツは壁になる。カンマ一つ動かすためにデプロイを強いるのは、デプロイの無駄遣いだ。
だから初めてヘッドレスCMSを手にしたとき、私は行きすぎて、何もかもそこに入れた——UIのラベル、テーマの設定、コンポーネントの状態を、本文のすぐ隣のリモートのテーブルに。それは一つの障害モードをより悪いものと交換する。今やインターフェースのクロームはネットワーク越しに届き、国際化はAPI呼び出しになり、CMSのしゃっくり一つがCMSに依存する理由のないページを落としうる。答えはどちらか一方だったことは一度もない。それは、日々変わるものとシステムを定義するものとのあいだの契約だ。
CMSは物語的で可変なコンテンツを、そしてそれだけを受け取る——誰もリファクタリングを必要とせずに育ち変わっていくもの。このブログではそれはすべての記事、抜粋、トピックだ。私はソースコードに触れずに管理画面から書いて公開する。ポートフォリオではプロジェクトの解説、節目、スキルがそれにあたる。契約を一つ終えることはコンテンツの編集であって、リリースではない。デプロイなしに変える必要のある数少ないグローバル設定——お知らせ、著者のメタデータ、フィーチャーフラグ——の置き場所としても正しい。気まぐれに下書きし、直し、消すかもしれないものなら、それはデータベースに属する。
アプリケーションの振る舞いを決めるもの、あるいはコンパイラに検証してもらう必要のあるものは、すべてコードに残る。インターフェースの辞書が最も分かりやすい例だ。両サイトとも6言語にローカライズされているが、ナビゲーションのラベル、ボタンのテキスト、プレースホルダ、aria-labelはリポジトリ内の型付きJSONに置く。CMSから取ってくると、フレームの描画に遅延が加わり、ハイドレーションの途中でキーが欠けるリスクが出るからだ。ルーティングのルール、テーマの設定、アニメーションのタイミング、バリデーションのスキーマも同じで、これらはデータベースの行ではなくコンパイル時のチェックを求める。そして静的アセット——画像、アイコン、サムネイル——はプロジェクトに属し、そこではビルドが最適化でき、キャッシュが信頼でき、描画の経路にCMSのメディア往復が入らない。
どちらの箱にも入らないものがある。コメント、いいね、閲覧数、レートリミットの台帳、セッション——高頻度で、トランザクショナルで、本物の整合性を必要とするもの——は、執筆のために作られたCMSにも、デプロイのたびに再構築されるファイルにも属さない。コメントのスレッドには返信、認証チェック、モデレーションが要る。いいねのカウンタは静的な再構築を押しつぶし、CMSの書き込みAPIを這うことになる。レートリミットとアクセスログには、リアルタイムの仕事をする本物のデータベースが要る。それは三つ目の保管場所であり、それを他の二つのどちらかのふりをさせることが、両方の遅くて脆いバージョンに行き着く道だ。
物語はCMSへ。構造はコードへ。数え、刻み、絞るものはすべて、そのどれもしないデータベースへ。
設計とはたいてい、線を引き、そして都合のために動かすことを拒む行為だ。コンテンツとコードはライフサイクルが違う。そうでないふりをやめた瞬間、道具はこちらと戦うのをやめる。CMSは私にどこからでも公開させてくれる。リポジトリは、ビルド時に正しくなければならない部分を、実際にビルド時に正しく保つ。両者のあいだの境界だけが、そのどちらもが使っていて心地よい理由だ。
土台はできた。あとは建てるだけだ。