「確認のメールが、二通来ました」。お客様からそう言われて、記録を見た。たしかに、まったく同じ申込が、ほんの一秒ほどの差で、二件並んでいた。
一人の人が、一回申し込んだだけのはずだった。なのに、システムの中では二件になっている。通知も二通飛ぶ。管理する側から見れば、同じ人が二度申し込んだように見える。
一回のつもりが、二回になる
なぜ二件になったのか。理由は、いくつも考えられた。
送信ボタンの反応が遅くて、届いていないと思ってもう一度押した。あるいは、通信の都合で、同じ申込が二度送られた。どれも、ユーザーに落ち度はない。押した本人は、一回のつもりでいる。
問題は、その「一回のつもり」を、こちらが二回として受け取ってしまったことだった。
二つの処理が、同時に走っていた
もう少し細かく見ると、こういうことだった。
ほぼ同時に、二つの申込処理が走っていた。片方が「まだこの申込は登録されていない」と確かめ、登録しにいく。その最中に、もう片方も「まだ登録されていない」と確かめ、同じように登録しにいく。二つとも、相手の存在に気づかないまま、同じものを書き込んだ。
「先に確かめてから書く」という手順は入れていた。けれど、確かめてから書くまでのわずかな隙間に、もう一つが割り込んでいた。
一度に一つだけ、通す
直したのは、その隙間だった。
申込の処理に入る前に、鍵をかける。鍵を持っている間は、他の処理を待たせる。書き終えて鍵を返してから、次を通す。こうすれば、確かめてから書くまでの間に、別の処理が割り込めない。一度に一つだけが、順番に通っていく。
あわせて、同じ申込が二度来ても、二件めは「すでにある」と気づいて何もしないようにした。二重に届いても、結果は一件で変わらない。そういう作りに直した。
「一回しか来ない」は、成り立たない
この件で、前提を一つ捨てた。
ユーザーは一回しか押さない。通知は一回しか届かない。そう思って作ると、いつか裏切られる。現実には、ボタンは二度押されるし、同じ通知は二度届く。それは例外ではなく、ふつうに起きることだ。
だから、二度来る前提で作る。二度来ても、結果が変わらないようにしておく。「来ないはず」を守るより、「来ても大丈夫」にするほうが、ずっと堅い。
同時に来たら、どうなるか
いちばんの学びは、「同時」を意識するようになったことだ。
一件ずつ順番に来る前提でコードを読むと、たいてい正しく見える。けれど、二つが同時に来たらどうなるか。その目でもう一度読むと、隙間が見えてくる。確かめてから動くまでの、ほんの一瞬。そこに、もう一つが滑り込む。
派手なバグではない。ふだんは一件ずつ来るから、めったに起きない。だからこそ、忘れたころに、そっと二件になる。人の手が触れる入口を作るたび、「同時に来たら」を一度考えるようになった。