🇺🇸 This site is also available in English — View English page →
S
Sidekick Lab
by Ichiro Murata

テンプレートと本番がずれても、テストは何も言わなかった

サイト改修の作業中に、テンプレートを直しても本番のHTMLには反映されていなかった不具合が3件、実行方法によって結果が変わってしまうテストが1件見つかった。いずれも直した瞬間には何も起きず、次に誰かが動かしたときに初めて症状が出る、という共通点があった。

村田一朗|写真家・SideKick開発者

サイトの改修作業をしている最中に、本題とは別のところで4件の不具合を見つけた。いずれも「直したはずなのに直っていない」「テストが通っているのに壊れている」という種類のもので、共通しているのは、症状が出るのは次に誰かが再ビルドしたり再実行したりしたときであって、原因を作った時点では何も起きない、という点だった。今回はその4件と、そこから得た教訓を記録しておく。

テンプレートを直したのに、本番はそのままだった

3つのページで、同じ構造の問題が見つかった。ページの見た目は、共通のテンプレートから生成する仕組みになっているが、何らかの理由でテンプレート側だけを直して、実際に配信されている本番のHTMLを作り直すのを忘れる、ということが起きていた。

プロフィールページでは、6日前に本番側だけを直接修正していたため、次にテンプレートから作り直すと、その修正がまるごと巻き戻る状態になっていた。更新履歴ページでは逆に、新しく追加した4件の項目がテンプレート側に反映されておらず、全ページを作り直すと本番の履歴が消えてしまう状態だった。

いちばん長く気づかれなかったのは、英語版の「打ち出の小槌」のフッターだった。5週間にわたって、プライバシーポリシーと利用規約へのリンクが無いフッターを配信し続けていた。原因を調べていたとき、テンプレートのコメントに「英語ページが存在しないページへはリンクしない」という古い方針が書かれているのを見つけて、一瞬「これは仕様どおりなのでは」と誤解しかけた。実際にはその方針はすでに撤回されていて、コメントだけが消し忘れられていた。Gitの履歴でそのコメントがいつからあるか、方針自体がいつ変わったかを確認して、誤読を避けることができた。

「全部PASS」が意味していなかったこと

今回いちばん書く価値があると思っているのは、この件だ。

同じテストを2つの方法で実行すると、結果が食い違っていた。一方の実行方法ではすべて成功と表示されるのに、もう一方では失敗が出る。原因を調べると、テストの中身を確認する処理が、問題を見つけてもリストに記録するだけで、実行環境に対して「失敗した」と伝える処理を書き忘れていた。そのため、片方の実行方法から見ると、何を検査していようと必ず成功したことになっていた。

実際に検査が抜け落ちていた先では、ヘッダーのナビゲーション項目の数を、決め打ちの数値でチェックしていた。開発日誌のページを追加した時点で数が1つ増え、その後もう1ページ復活させて2つ増えていたが、その食い違いは5週間以上、誰にも気づかれていなかった。

そして今回の作業中も、「テストは全部成功している、意図しない変更は無い」という報告を何度もしていた。その「全部成功」は、実際には壊れていた検査については何も保証していなかった。テストが通っていることと、テストが機能していることは別だ、というごく基本的なことを、今回あらためて思い知らされた。

差分の要約が、見えない変更を隠していた

フッターへのリンク追加を確認したとき、変更内容を要約して「意図しない変更の混入は無い」と判断したが、実際には英語版21ページの先頭にあった、目に見えない制御文字が同時に取り除かれていた。差分を要約する際に、空白の増減を無視する方法を使っていたため、その1文字だけの変更が、他の空行の変化に紛れて見えなくなっていた。

結果として実害は無かった。すべてのページですでに文字コードを別の方法で宣言しており、その制御文字自体が無くても問題は起きない構成だったからだ。問題なのは、実害の有無ではなく、「意図しない変更は無い」と言い切ってしまったことだった。

見えてきた共通点

4件に共通しているのは、次のようなことだ。

  • 「成功」と表示するスクリプトは、意図した結果になったことまでは保証しない
  • 「全部成功」と出るテストは、検査そのものが機能していることまでは保証しない
  • 差分を要約する処理は、何を無視しているかを意識していないと、無視したものはそのまま見えなくなる
  • どの不具合も、症状が出るのは次に誰かが動かしたときで、原因を作った瞬間には何も起きない

だからこそ、定期的に「テンプレートと本番が一致しているか」「テストは本当に失敗できるのか」を確かめる仕組みが必要だと考え、今回それを実際に作った。

今回入れた対策

テンプレートと本番のHTMLが食い違っていないかを検出するテストを、サイト全体・打ち出の小槌・開発日誌の3つの区分に分けて追加した。あわせて、検査の失敗が実行結果へきちんと伝わるように直し、ナビゲーション項目の数についても、決め打ちの数値をやめて、テンプレートから実際の項目数を数える方式に変えた。

ただし、この対策にも限界がある。項目数を数える処理は、テンプレートの文字列を単純に数える方式のため、条件によって出したり消したりするリンクがある場合、その条件分岐までは正しく解釈できない。英語版のリンクを出さない設定でページを作る場合には、この数え方はそのままでは使えない。これはコード上に明記して残してある。

また、検査の失敗が実行結果へ伝わるようにしたことで、1つの確認処理の中で最初の失敗が見つかった時点で、それより後の検査が実行されなくなった。すべての問題を一度に洗い出せるわけではなく、直しては再実行する、という手順が必要になる。

まだ残っていること

今回見つかった4件はいずれも直したが、同じ種類の「テンプレートと本番のずれ」や「機能していない検査」が、今回確認した範囲の外に残っている可能性は否定できない。今回作った検出の仕組みも万能ではないため、しばらくは実際に運用しながら、抜けがないかを確かめていく必要がある。