自分のタスクを全部消した — 「サーバーが正しい」という前提の落とし穴 — 制作日誌 #9
ビジネス

自分のタスクを全部消した — 「サーバーが正しい」という前提の落とし穴 — 制作日誌 #9

アカウントを作り直してログインしたら、中身が空だった。犯人は、自分が書いた3行の安全対策。復元元が無いことに気づくまで数分、無料プランにバックアップが無いと知るまでさらに数分。

KIYODO00
#個人開発#データ同期#障害対応#バックアップ#制作日誌

自作のタスク管理アプリで、自分のデータを全部消した。

ログイン周りの挙動を確かめようとして、テスト用のアカウントを作ったり消したりしていた。その流れで、普段使っている自分のアカウントも一度削除し、同じGoogleアカウントで作り直して再ログインした。

画面には、何も無かった。 タスクもリストもメモも、すべて空。

被害者は自分だけ(一般ユーザーのデータは無事)だったが、原因を突き止めるほど背筋が寒くなったので、記録として残しておく。

犯人は、自分で書いた「安全対策」だった

コードを追って原因はすぐ分かった。同期処理の冒頭に、アカウント切替の安全対策を入れていたのだ。

端末に保存されている持ち主のIDと、いまログインしている人のIDが違ったら、端末のデータを全部消す

意図は正しい。人にスマホを貸したとき、前の人のタスクが残っていたら事故になる。だから切り替わったら消す。当然の設計に見える。

この設計が成立していたのは、**「消しても、サーバーから取り直せる」**という前提があったからだ。端末はあくまで写しで、正本はサーバーにある。だから消して良い。

その前提が、今回だけ崩れていた。

なぜ崩れたか

アカウントを一度削除して作り直すと、同じメールアドレスでも、システム上は別人になる(内部で振られるIDが変わる)。私のIDは削除前と後で別物になっていた。

そこで何が起きたか。

  1. 新しいIDでログインする
  2. 端末に残っている持ち主のIDは古いほうなので、一致しない
  3. 安全対策が発動し、端末のデータを全消し
  4. サーバーから取り直そうとするが、新しいIDのデータはサーバーに存在しない(作りたてだから空)
  5. 端末も空、サーバーも空

しかも、テスト中に何度も切り替えていたので、この処理はそのたびに走っていた

つまり 「サーバーが正本」という前提は、サーバーが空のときには成立しない。にもかかわらず、コードは前提が崩れているかどうかを一切確認せず、先に消していた。

そして、バックアップが無かった

「まあサーバー側の日次バックアップから戻せばいい」と思って確認したら、使っていたデータベースの無料プランには自動バックアップが無かった。過去のある時点に戻す機能も付いていない。

さらに、削除されたアカウントに紐づく古いデータ行も残っていなかった。サーバーから戻す手段が、まるごと無い。

このとき初めて「自分のサービスのデータは、いま誰も守っていない」と理解した。

どう復旧したか

結果的には、ほとんど戻せた。使ったのは2つの経路だ。

1. たまたま手動で取っていた控え 数週間前に、なんとなく手で取っておいたデータの控えがパソコンのディスクに残っていた。タスク152件、リスト5件、メモ39件。これを新しいIDに入れ直した。

2. カレンダー側に残っていた分 このアプリは時刻付きのタスクをGoogleカレンダーにも書き出す作りになっていた。つまりカレンダーが意図せぬ第2の控えになっていた。ここから、控えの日付以降に増えた未完了のタスクを拾い直した。

最終的にタスク163件・リスト5件・メモ39件まで戻った。設定も端末の同期から復活した。

**戻らなかったのは、控えを取った日以降に追加された「時刻の無いタスク」**だけだ。カレンダーに書き出されるのは時刻付きのものだけなので、そこに穴が残った。

恒久対策としてやったこと

1. 自動バックアップを作った データベースの全テーブルを毎日ダンプして保存するスクリプトを書き、パソコンの定期実行に登録した。30日分を保持する。手で取った控えがたまたま残っていたから助かった、という状況を二度と作らないためだ。

2. 「消す」のをやめて「退避する」に変えた 安全対策の処理を書き替えた。消す前に、いまのデータを持ち主のIDごと別の場所へ退避する。 そのうえで、

  • 持ち主のIDが未設定なら、消さずにそのまま採用する
  • 本当に別の人へ切り替わったなら、退避してから初期化する
  • 元の持ち主が戻ってきたら、退避したものを復元する

こう変えると、間違って発動しても失われない。安全対策が破壊的である必要は、どこにも無かった。

教訓

  • 「正本はあちら側にある」は、あちら側が空でないことを確認して初めて成立する。 前提を検査せずに破壊してはいけない
  • 削除して作り直したアカウントは別人。同じメールアドレスでも同一とは限らない
  • 消す処理は、まず退避に置き換えられないか考える。 復元可能なら事故が事故にならない
  • 無料プランにバックアップがあると思い込まない。 実際に契約内容を見る
  • 意図しない第2の控えが命を救うことがある。 今回はカレンダー連携がそれだった

いちばん怖かったのは、これが**「安全のために書いたコード」**に起因していたことだ。守るつもりで書いた処理が、いちばん確実にデータを消していた。防御的なコードほど、発動条件を疑ったほうがいい。

この記事で触れているアプリ

本稿の題材は、筆者が個人開発している iOS アプリ THE TASK:AI下調べToDoリスト(App Store・無料)です。書いたタスクをAIが着手できる状態まで補完する、という発想で作っています。他の回は制作日誌シリーズにまとまっています。

あわせて読みたい

コメント (0)

まだコメントはありません。最初の一言を残しませんか?