見た目は、完璧だった。
スマホ用に、画面の横から出てくるメニューを作った。開くアニメーションも、項目の並びも、閉じるための×印も、思った通りに表示されている。なのに、その×が押せない。タップしても、何も起きない。閉じられないメニューほど、間抜けなものはない。
見えているのに、反応しない
最初は、×を閉じる処理の書き間違いを疑った。
けれど、処理は正しかった。試しに×を別の場所へ動かすと、ちゃんと閉じる。位置を元に戻すと、また反応しない。見えているのに、押せない。これは、ボタンそのものではなく、その上に「見えない何か」が重なっている、という典型だった。
グローバルなルールが、漏れていた
犯人は、メニューの中のリンクを囲っていた要素だった。
その囲いに、ナビゲーション用の枠を使っていた。ところが、サイト全体には「ナビゲーションは画面に固定して、いちばん手前に出す」というルールが、ずっと前から書いてあった。新しく作ったメニューの中の囲いにも、そのルールが効いてしまった。
結果、その囲いが、透明なまま×印の上に大きくかぶさっていた。目には見えない。でも、タップを全部吸い込んでいた。だから×は、押せなかった。
名前が同じだと、巻き込まれる
直し方は、囲いに使う要素を変えるだけだった。同じ役割でも、全体のルールに巻き込まれない書き方にする。それで×は、すぐに反応するようになった。
怖かったのは、これがコードを読むだけでは見つからなかったことだ。一つひとつの部品は、どれも正しい。組み合わさって、しかも全体の古いルールと触れたときだけ、不具合が出る。静かに読んでいるだけでは、まず気づけない。
一つひとつ正しくても、全体は壊れる
このバグが教えてくれたのは、部分と全体は違う、ということだ。
メニューも、囲いも、×印も、単体ではどれも正しい。なのに、組み合わさり、さらにサイト全体の古いルールと触れた瞬間に、壊れた。誰か一人のミスではない。正しいもの同士の、予想しなかった重なりだった。
コードを読むレビューは、部分の正しさを見るのは得意だ。けれど、こういう「全体で初めて出る」不具合は、すり抜けやすい。だから、読むだけで終わらせない。できあがったものを実際に動かして、本当に意図どおりかを、目ではなく動作で確かめる。
「押せるか」は、実際に押して確かめる
見つけられたのは、実際にその場所を「押したら何が反応するか」を、機械に調べさせたからだ。
見た目が正しいことと、押せることは、別だ。表示は、目で確かめられる。けれど「重なり」は、目では見えない。だから、できあがった画面に対して、実際にその座標を押させてみる。何が手前にいるかを、人の目ではなく、当たり判定で確かめる。
きれいに見えるほど、油断する。見えているものより、見えていない重なりのほうが、よほど人を裏切る。