1語足すために、6か所を直した
用語集に13語を足しました。作業そのものは半日で終わりましたが、1語につき触った場所は6か所ありました。
数が見えたので、書いておきます。
1つの情報が2か所に分かれていると、追加のたびに何が起きるかという話です。なぜ分けたのか、分けたことで何を手で守る必要が出たのか、そして食い違ったときに何も起きないまま壊れる箇所を書きます。
用語集は2か所に分かれている
このサイトの用語集は、解説の本文をCMSの固定ページに置いています。分野ごとに1ページ、いまは8ページあります。文章なので、コードを触らずに直せるほうが都合がよいからです。
いっぽうで、用語の一覧と検索はコード側に持っています。語・読み・1行の説明・置き場所の4つだけを並べた配列です。
export type GlossaryTerm = {
t: string; // 用語
r: string; // 読み(検索で使う)
s: string; // 1行の説明
c: string; // 分野
id: string; // そのページ内の位置
};
なぜ一覧まで本文から作らないのか。検索のために129語ぶんの本文を毎回取りに行くのは重すぎるからです。本文は全部で9万字近くありますが、この4つだけなら十数キロバイトに収まります。読み込んだ時点で手元にあるので、入力した瞬間に絞り込めます。
1語足すと、6か所になる
分担そのものは理由があって決めたものです。ただ、追加のときにやることは1か所では終わりません。
| 場所 | 足すもの |
|---|---|
| CMS:本文 | 見出しと解説の本体 |
| CMS:ページ冒頭の索引 | その用語へのアンカーリンク |
| CMS:索引の件数ラベル | 「この分野の用語(14)」の数字 |
| コード:用語の配列 | 語・読み・説明・分野・id の1行 |
| コード:関連記事の対応表 | id と記事スラッグの組 |
| コード:コメント内の語数 | 「用語は116語あり」という説明 |
13語だと78か所になります。実際には分野ごとにまとめて入れたので、手数はもっと少なく済みました。それでも1語の追加が6つの独立した編集に分かれているという構造は変わりません。
食い違ったときに何が起きるか
ここが問題の中心です。どれか1つを忘れても、エラーは出ません。
| 忘れた場所 | 見え方 |
|---|---|
| 本文だけ足した | 検索に出てこない。書いたのに誰も辿り着けない |
| 配列だけ足した | 検索には出る。押すとそのページの先頭に着く |
| 索引リンクを忘れた | ページの中からは見つけられない |
| 件数ラベルを忘れた | 数だけが合わない。誰も気づかない |
存在しないアンカーを指すリンクは、404になりません。ブラウザは黙ってページの先頭を表示します。
検索結果から押して、用語集のページが開く。一見うまくいっているように見えます。探していた語が見つからないのは、読む人の側からは「自分の見落とし」に見えます。
並び順という、どこにも書かれていない決まり
作業していて気づいたことがあります。用語の並びは読みの順ですが、並べ替える処理はコードのどこにもありません。手で並べた順のまま出しています。
そして、その「読みの順」がどういう規則なのかも、どこにも書かれていません。既存の並びから読み取る必要がありました。
| 並び | 読み取れること |
|---|---|
| ひらがなの語 → カタカナの語 | 文字コードの順に並んでいる |
| エスピーエフ → エーレコード | 長音符は「ス」より後ろ |
| ティーエルエス → テキストレコード | 小さい「ィ」は「キ」より前 |
つまり、日本語としての五十音順ではなく読みの文字列をそのまま比べた順でした。13語を正しい位置に入れるには、この規則を先に確定させる必要がありました。
ここも、間違えてもエラーは出ません。順番が少しおかしいだけです。誰も気づかないまま、少しずつ崩れていく種類の決まりです。
送ったものと、保存されたものを突き合わせた
CMSの本文は、既存の1万字ほどの中に新しい塊を差し込む形になります。差し込む処理を間違えて、もともとあった文章を壊していないかが心配でした。
そこで、送る前の文字列と、保存された後に取り直した文字列で、長さと簡単なハッシュを比べました。
// 送った内容
{"sent": "12685:c5ada48b"}
// 保存された内容を取り直したもの
{"back": "12685:c5ada48b"}
見た目の確認だけでは、1文字消えたことに気づけません。数字が一致するかどうかなら、見落としようがありません。6ページぶん、すべて一致しました。
「ページを開いて、おかしくないことを確かめる」は、おかしい場所を知っているときにしか働きません。
どこが壊れたか分からない状態で使えるのは、壊れていないことが1つの値で言える方法だけです。
直し方は3つあって、まだどれも選んでいない
| 案 | 得るもの / 手放すもの |
|---|---|
| 本文もコードに移す | 置き場所が1つになる / 文章を直すたびにデプロイが必要になる |
| 索引を本文から自動で作る | 手作業が消える / 検索のために本文を全部読む必要が戻る |
| 食い違いを検知する仕組みを置く | 分担は変えずに済む / 検知できるのは、検知すると決めたものだけ |
今回は、どれも入れずに手で6か所直しました。13語という数では、まだ仕組みを作るより手で直すほうが速いという判断です。
ただ、この判断は数が増えれば逆転します。次に足すときには、少なくとも3つめ——配列のidが本文に実在するかを確かめるだけの確認を先に用意するつもりです。並び順が規則どおりかも、同じ場所で見られます。
今回の学び
まず、置き場所を分ける判断には、必ず「同時に直す」という宿題が付いてくるということ。分けた理由は正しくても、宿題のほうは残ります。分けるかどうかを決めるときに、その宿題の重さまで数えておく必要がありました。
次に、エラーが出ない不整合がいちばん残ること。存在しないアンカーは404になりません。件数が1つずれても誰も止めてくれません。止まらない種類の間違いは、止まる間違いより長く生き残ります。
そして、コードに書かれていない決まりは、既存のものから読み取るしかないこと。並び順の規則は、どこにも書いていないのに確かに存在していました。読み取れたのは既存の116語が揃っていたからで、もし途中で1つ崩れていたら、崩れたほうを正解として続けていたはずです。
この記事を共有する
関連記事

細かく刻んでも直らなかった、経路を変えたら一度で通った
記事のアイキャッチ画像を、CMSへ入れる作業をしていました。画像を文字列に変換して、少しずつ送り込む方法です。 ところが、ときどき壊れます。送った文字列と、届いた文字列が違う。 対処として分割をどんどん細かくしていきまし […]

長さが合っているのに、中身が壊れていた
画像を分割して送ったら、長さは1文字も違わないのに真っ黒な画像が上がりました。どこで壊れたかを見つけるまでの遠回りと、検証をどこに置くべきかの話です。

通ったビルドが、何も直していなかった
codegenもビルドもコミットもpushもデプロイも、すべて成功した。それでも直したかったものは1つも直っていなかった。変更が丸ごと消えたことで辻褄が合ってしまい、検査をすり抜けた話と、それを見つけるための確認について。