自動で回したコードレビューで見つけた「緑なのに守れていない検証線」を、勉強のためにまとめたものです。
写真日記アプリ(綴Photo)は、言葉や設定を端末内のデータベースに持ちます。アプリを更新して DB の構造(スキーマ)が変わるたび、既存ユーザーの古い DB を新しい構造へ「移行(マイグレーション)」します。ここが壊れると、ユーザーが綴った言葉が静かに消えうる。今回のレビューで浮かんだのは、その移行を守る検証線が、緑のまま腐っていたことだ。
この記事で扱う観察ポイント
- そもそも「マイグレーション」と「スキーマの写し」とは何か
- テストが緑なことと、本番の移行が安全なことが一致しないケース
- 「写しが最新か」を機械でチェックする一行を足すという発想
コードで起きていたこと
アプリの DB は版を重ねて、いまは12版だった。ところが、保存されていたスキーマの写しは 10版で止まっていた。11版・12版の写しが無い。
移行のテスト自体はあって、緑だった。ただしそれは、古い版のスキーマを手書きで組み直して、そこから移行を流す形のテストだ。手書きで再現した範囲は確かに通る。
つまり「テストが緑」は「移行が安全」を意味していなかった。
なぜそうなりやすいか
写しの更新は、間取りを変えた本人が手で踏む工程で、忘れてもその場では何も起きません。アプリは動くし、テストも緑のままです。痛むのは、本番ユーザーが古い DB を抱えて新版を開いた、ずっと後になります。「いま困らない・後で効く」工程は、こうして静かに置き去りになります。
改善の方向
現行(12版)のスキーマを写しとして書き出し、そのうえで CI に一行足した。コードは AI に書いてもらい、私が決めたのは「写しが最新かを毎回機械で踏む」という方針だ。
# CI に足したチェック(要点)
# 現行スキーマをもう一度書き出し、写しの置き場に動きが出たら落とす
- run: |
dart run drift_dev schema dump <db> drift_schemas/
test -z "$(git status --porcelain drift_schemas/)"書き出しは決定的(同じコードからは同じ写しが出る)なので、差分が出る=「間取りを変えたのに写しを取り直していない」を意味します。これで「写しが古いまま緑」を機械が止めます。なお、無い版(11版)の写しは現行コードからは作れないため置いていない。その区間の移行は手書きテストが踏んでいるので、検証は二段で残る。
追記(2026-07-28): 初版のこの記事では、判定を git diff --exit-code と書いていた。版が上がるのは、間取りを変えたときの一番ふつうの形です。実際、この縛りを入れた次のスキーマ変更(12版→13版)で、新版の写しが15日間不在のまま緑が続いた。いまは、まだ git に登録されていないファイルも含めて見る形(git status)に直してある。
学びポイント
「テストが緑」と「本番のデータ移行が安全」は別物です。とくに検証が「手書きで再現した過去」に対して通っているとき、現行の本物とのズレは緑をすり抜けます。基準(スキーマの写し)が最新かどうかを、人の記憶でなく機械で踏ませる一行を置いておきます。
このテーマの括り
この観察は「緑は『壊れていない』ではなく『確かめた範囲では壊れていない』」という一般則の一例です。
| 緑に見えていたもの | 実際に確かめていなかったもの | 足した縛り |
|---|---|---|
| 手書き旧スキーマからの移行テスト | 現行スキーマの写しが最新か | 再書き出し + 差分検出を CI に常設 |
検証線は、置いた瞬間がいちばん信頼できて、放っておくと基準がコードから少しずつ離れます。離れたことに気づく仕組みまでを、検証線の一部として持っておきたい。
おわりに
検証線を足すときは、その線が将来も最新を指し続けるか——を一緒に考えておきたい。基準が古びていく検証は、放っておくと「守っているつもりの過去」だけを守り続けます。この種の死角は、検証がいちど緑で通ったあと、基準そのものを更新する工程が別に隠れているときに出やすいです。
この記事は2026年6月時点の自分の理解で書いています。仕様や認識が変わってる可能性があります。