出力を契約する ― 配ったあとも中身を変えられるようにする
シリーズ・第 2 回 — 「個人で出版ツールを作って配るまで」(全 5 回予定)。前回は全体像と前提を共有しました。各回は単独でも読めます。一覧は シリーズの記事一覧 から。今回のテーマは「配ったあとも、中身を変えられるようにしておく」です。
自分だけで使う道具なら、いつでも自由に作り変えられます。問題は、公開して他の人が使い始めたあとです。
たとえば設定キーをひとつ改名しただけで、その古いキーを使っていた利用者の環境は動かなくなります。配ったあとは、利用者が頼っている部分を気軽に変えられない。「外から見えるものは、いつか誰かが当てにする」——これは Hyrum の法則として知られる、ごく当たり前の現象です。
そこで配る前に決めておきます ― 何を約束として固定し、どこは自由に変えてよいことにするか。crofty はその約束を「出力」に置きました。
入力か、出力か
ここでの「入力」と「出力」は、道具(crofty)が受け取るもの(あなたが書く記事や設定)と、生み出すもの(dist)です。約束をどちらに置くか、二択になります。
| 入力を契約する | 出力を契約する | |
|---|---|---|
| 固定するもの | 設定キー・ファイル構成・テーマ内部 | 生成 HTML に必ず入る項目 |
| 内部の変更 | 利用者の環境が壊れやすい | 契約さえ守れば自由 |
| つらくなる例 | キー名の改名、部品の作り替え | 契約を破ったときだけ |
入力を契約すると内部実装が約束になり、出力を契約すると作り方が自由になります。crofty が選んだのは後者です。
「契約」の正体 ― 実物を見る
言葉だけだと抽象的なので、実物を見ます。crofty が生成する記事ページの <head> には、必ず次が入っています。
<!-- 生成された HTML(抜粋) -->
<html lang="ja">
<head>
<title>記事タイトル · サイト名</title>
<link rel="canonical" href="https://example.com/posts/hello/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- + フィード(/feed.xml)があり、外部へ勝手に通信するタグは無い -->
</head>
この「必ず入っている項目」こそが契約です。lang や canonical が欠けたページを、crofty は出力しません。逆に、ここに無いもの(テーマの作り方、HTML の組み立て方)は、自由に変えてよい部分です。
文書ではなく、機械で守る
契約は文章で書くだけだと、いつか実装とずれて腐ります。そこで crofty doctor が、ビルドした dist が契約を満たしているか毎回チェックします。
$ crofty doctor
✓ output contract: all good
Checks: canonical link, feed, <html lang>/<title>/viewport, no phone-home.
これで契約は「努力目標」ではなく「機械が守る線」になります。内部をどれだけ作り替えても、doctor が通る限り、利用者のサイトは約束どおりに保たれます。
それでも、入力はゼロにはできない
出力を契約しても、入力面(記事の frontmatter や設定)は残ります。大事なのは、その線引きです。
| 場所 | 扱い |
|---|---|
| crofty が所有するファイル | crofty が書く |
利用者のもの(hugo.yaml など) |
書き換えず、案内にとどめる |
| 見た目のカスタマイズ | あとから勝つ層(crofty theme eject の custom.css)で上書き |
上書きしても doctor が契約を点検するので、「自由に変えていい場所」と「守る場所」は混ざりません。
どこにでも効く考え方
これは crofty に限りません。「公開 API を、内部の作りではなく、外から見える振る舞いで定義する」という一般的な作法です。
- ライブラリ ― 内部構造でなく「振る舞い」にバージョンの約束(semver)を切る
- CLI ― 中の実装は自由にしつつ、出力フォーマットを安定させる
- テーマ ― 部品名やクラス名でなく、生成物の保証を約束する
約束する面=外から見える面を、意識して小さく選ぶ。何を凍らせ、何を動かせるようにしておくか。配る道具の設計は、その線引きから始まります。
← 前の記事:書いたものを自分の手元に置く | 次の記事:多言語サイトの設計 →