順番で決まる名前は、いつか壊れる
用語集の102語と、記事のあいだにリンクを張ろうとしました。
ところが張る前の下調べで、そのリンクが最初から壊れる仕組みになっていることが分かりました。順番を変えただけで壊れます。
並び順から自動でIDを作ることの危うさ、公開前の記事へリンクしてしまっていた話、そして「直したつもり」で終わらせないための確認方法です。
用語ページの中身を、直接指せるようにしてある
用語集は分野ごとに1ページで、1ページに10〜18語ほど入っています。個々の語は見出しに id を振ってあり、こう書けば特定の語へ直接飛べます。
/glossary/security/#waf
記事から用語へリンクするには、この id が要ります。そこで中身を確認しました。
半分以上が、意味のない名前だった
IDは用語名から機械的に作っていました。英数字だけを残し、それ以外を捨てる方式です。
| 用語 | できたID |
|---|---|
| WAF | waf |
| DNS | dns |
| ネームサーバー | term |
| 名前解決 | term-2 |
| サブドメイン | term-3 |
日本語の語は、英数字を残すと何も残りません。空になったものには、衝突しないように連番を振っていました。
102語のうち55語がこの状態でした。
なぜ、これが壊れるのか
問題は読みにくさではありません。この連番が「何番目に出てきたか」で決まることです。
追加前 追加後
term ネームサーバー term ネームサーバー
term-2 名前解決 term-2 【ここに1語追加】 ← 割り込む
term-3 サブドメイン term-3 名前解決 ← ずれた
term-4 サブドメイン ← ずれた
用語を1語足すと、それ以降のIDが全部1つずつずれます。
そして、ずれてもエラーは出ません。ページは正常に表示されます。リンクを踏んだ人が、ページの先頭に着地して「あれ?」と思うだけです。
IDは、他の場所から指すための名前です。指す側は、指される側の並び順を知りません。
用語集を充実させるほど、つまり良い方向に手を入れるほど、リンクが壊れていく。更新すると壊れる仕組みを先に作ってしまっていました。
手で書いて、増えないようにした
自動生成をやめ、102語すべてに固定のIDを手で割り当てました。
"ネームサーバー": "nameserver",
"名前解決": "name-resolution",
"サブドメイン": "subdomain",
手で書くのは面倒に見えますが、面倒なのは最初の1回だけです。追加する語は1行足すだけで、既存のIDは動きません。
あわせて、対応表に無い語が来たら止まるようにしました。
未登録の語に自動で連番を振る作りだと、また同じ問題が静かに戻ってきます。止まれば、その場で1行足すだけで済みます。
「気を付ける」で運用するより、間違えられない形にしておくほうが確実です。
もうひとつ、公開前の記事へリンクしていた
用語集には「関連記事」を載せています。ここも確認したところ、22件のうち8件が、まだ公開していない記事を指していました。
用語集のページは公開済みです。つまり読者から見ると、リンクを踏むと404になります。
原因は単純で、記事を書く前提でリンクを先に書いていたためです。
そこで、公開済みの記事の一覧を持たせ、そこに載っていないリンクは出力しないようにしました。記事を公開したときに一覧へ1行足せば、リンクも一緒に出てきます。
ついでに、リンクの文字をスラッグから記事タイトルに変えました。apex-vs-www と書かれても、押す前に中身が分かりません。
直したあと、本当に直ったかを確かめる
ここが今回いちばん大事な部分です。
本番のページを書き換える必要がありましたが、「更新しました」という応答は、内容が正しいことを意味しません。途中で一部だけ置き換わっていても、成功として返ってきます。
そこで、手元で作ったHTMLと、本番に入ったHTMLを数値に変換して突き合わせました。
手元で組み立てたHTML → 数値に変換 → A
本番に入ったHTML → 数値に変換 → B
A と B が一致 → 1文字も違わない
文章を1文字ずつ見比べるのは現実的ではありません。全体を1つの数値に潰してしまえば、一致するかどうかだけを見れば済みます。
8ページすべてで一致しました。さらに、書き換えたあとで全リンクの飛び先が実在するかも機械的に確認しています。
| 確認したこと | 件数 | 壊れ |
|---|---|---|
| 記事 → 用語集のリンク | 230 | 0 |
| 用語集 → 記事のリンク | 38 | 0 |
| 下書きのまま残っているか | 10件すべて | — |
268本のリンクを手で踏んで確かめることはできません。目視で確認できない量になった時点で、確認する仕組みのほうを用意する必要があります。
「たぶん大丈夫」と「1件も壊れていないことを確かめた」は、別のことです。
今回の学び
まず、外から指される名前は、中の都合で変わってはいけないこと。並び順・件数・登録した順番といった内部の事情でIDが決まると、中を整理するたびに外が壊れます。名前は約束なので、勝手に変えられない形にしておくべきです。
次に、自動生成は、入力の性質を確かめてから使うこと。英数字を残す処理そのものは間違っていません。日本語の用語に対して使ったことが間違いでした。半分以上で空になると分かっていれば、最初から別の方法を選んでいたはずです。
そして、足りないときは黙って埋めずに止めること。埋めてくれる親切な仕組みは、間違いも一緒に埋めます。止まれば気づけます。
最後に、直したことと、直ったことは違うこと。更新が成功したという応答は、内容が正しい証明にはなりません。手元の正解と本番を突き合わせて初めて、直ったと言えます。この確認自体が数秒で終わるなら、やらない理由はありません。
関連記事

使っていないものは、書かない
広告を検討して手が止まったのは、広告ではなくプライバシーポリシーが無かったこと。テンプレートを貼らなかった理由と、置き場所・管理の仕方をどう決めたか。

1語1ページにしなかった理由
用語集を作るとき、1語につき1ページにするか、まとめて1ページにするか。解説を厚くすると決めた時点で前提が変わり、最初の判断を見直すことになった。薄いページを大量に作るリスクと、本番のPHPを触れないという制約から、分野別8ページという形にたどり着いた記録。
自分のブログに記事が投稿できない — WAFの誤検知と、渡し方を変える解決
自分のブログに、自分で書いた記事が投稿できなくなりました。 原因はサーバーのWAF(Webアプリケーションファイアウォール)でした。記事の本文に含まれるコードが、攻撃と誤検知されて遮断されていたのです。回避を4種類試して […]