一括処理が「全記事」に当たった:書く前に数える、テストは壊して確かめる
トレカダッシュ 開発の記録 / 2026年10月
iOS アプリ「トレカダッシュ」で、記事の状態をまとめて直す新しい処理が、最初に流したとき、対象にするつもりのなかった記事まで、全部に当たりました。別のサイト由来の 18 件が、誤って、表示に戻っていました。事故の直し方と、その後に、同じ穴をふさぐテストを作ったとき、「そのテストが、本当に効くか」を、どう確かめたかを、HANDOFF の記録で書きます。
このサイトには、トレカダッシュの作品ページがあります(トレカダッシュ)。ここに書くのは、開発の記録です。
何をする処理だったか
アプリには、出品の価格が妥当かを調べる「価格の関門」があります(別の記事に書きました)。この関門で、価格だけを理由に非表示にされた記事のうち、商品の取り違えが原因で、本当は正しい記事を、表示に戻す処理を足しました。戻す条件は、「正しい商品の定価と、出品価格が一致すること」です。
事故:全記事に当たった
この処理は、最初、取り込み元を区別せず、全記事に当たりました。その結果、別のサイト(Amazon、カードラボ、ミニストップなど)由来の記事 18 件が、表示に戻ってしまいました。本来、非表示のままであるべきものです。
直し方は、二つです。
- 範囲を絞る。処理が当たる記事を、その取り込み元のものだけに、限りました(サイトの識別子が、その取り込み元で始まるもの)。
- 戻したものを、元に戻す。誤って表示に戻した 18 件は、記事の状態の履歴(
statusHistory)から特定して、元の状態(非表示で、価格で却下されたもの)に戻しました。
ただし、この 18 件には、取り返せなかったものがあります。処理が、元の定価の欄を、出品価格で上書きしていました。値は、出品価格のままです。
原因は、書き込みの前に、対象の範囲を、数えていなかったことでした。記録にも、そう書いてあります。「一括の書き込みは、対象の範囲を先に数えてから」。
同じ穴をふさぐ、テストを作る
この日の点検で見つかった問題(9 種セットの誤分割、単品カードの混入、カードではない商品の混入など)を、二度と起こさないために、テストを作りました。catalog-guards.test.js に 66 件、ほかと合わせて、全 6 本を、1 つの手順(run-all.sh)で通せるようにしてあります。
あわせて、毎日の運用連絡に、警告を足しました。突き合わせの取りこぼし率が、基準(抽選図鑑 80%、ポケチュー 75%、X のまとめ 75%)を下回ったとき、30 時間動いていないとき、商品リストに、単品カードや、カードではない名前の商品が現れたときです。判定は、副作用のない純粋な関数で書いてあり、直れば、次の回で、自然に消えます。
テストが効くかを、壊して確かめる
テストは、書いただけでは、効いているか分かりません。常に通るテストは、何も守っていないかもしれないからです。そこで、本番のコードの複製の、規則を 1 つずつ外して、テストが失敗することを、確かめました。
- 規則を 1 つ外す(壊す)。
- テストを流す。
- 失敗すれば、そのテストは、その規則を、守っている。
この手順で、6 種類の改変を試して、6 種類とも、テストが失敗しました(全部、検出できた)。
運用のきまりも、記録に残しました。functions/index.js を触ったら、配備の前に、必ず、全テストを通します。
分かったこと
一括の書き込みは、先に数える。テストは、壊して確かめる。
- 書く前に、「何件に当たるか」を数える。下見をせずに流すと、範囲の間違いに、書き終わってから気づきます。
- 元に戻せる形で書く。履歴から特定できたので、18 件を戻せました。ただし、上書きした欄は、戻せません。
- 通るテストより、壊れたら落ちるテスト。規則を外して、落ちることを見て、はじめて、そのテストを信じられます。
この記事は、HANDOFF(§272)の記録(2026年10月7日)から書きました。件数は、記録に書かれたものです。
この話に出てくるもの
- 確認できなかったときに、通していた — 同じ「価格の関門」の、別の記録
- 「重複は実質ゼロ」と数えたのに、監査は112組を出していた — 数え方を疑った、別の記録
ほかの記録
- 「9種セット」を中身ごとに分けて、偽の商品が80個できていた — ポケモンカードの9種セットは1つの商品なのに、中身ごとに分けて、実在しない商品が80個できていた。入口を止め、親22件を戻し、子190件を外し、偽の商品を消した記録。
- Firebase Auth:アプリを完全に終了すると、匿名アカウントが量産された(currentUser の復元待ち) — 「アプリを落とすと、また Apple のサインインを求められる」。管理画面を開くと、19人中17人が使い捨ての匿名アカウント。起動直後に currentUser を同期チェックしていた競争を、addStateDidChangeListener で直した記録。
- 「重複は実質ゼロ」と数えたのに、監査は112組を出していた — 重複を統合する処理が、毎晩、先頭のジャンルの途中で時間切れになっていた。「ゼロ」と数えた自分の測り方が間違っていた。持ち回りに直して112組を0組にした記録。
コメント
感想や、記事の間違いの指摘は、ここへ。書くには、GitHub のアカウントが要ります。
押すと、giscus(giscus.app)と GitHub に接続します。押さなければ、接続しません。詳しくはあつかいに書いています。