データベースの更新が1つ飛ばされて当たった事故と、番号の順番を検査する仕組み
テスト環境で、データベースのマイグレーション(表や列の形を変える更新)の028と029が当たらないまま、030だけが当たりました。原因は、更新の道具が番号の順番を確かめていなかったこと。抜けや順番の崩れを見つけたら何もせずに止まる検査を足した記録です。

マイグレーション(データベースの表や列の形を変える更新)が飛ばされる事故は、当てる前に番号の抜けと順番の崩れを検査し、見つけたら何もせずに止まる作りにすれば防げます。私たちのテスト環境では、028 と 029 が当たらないまま 030 だけが当たり、その原因は、更新の道具が順番を確かめていなかったことでした。
不動産の業務アプリ(Kaitori Base)のテスト環境で、データベースの更新(マイグレーション)が、順番どおりに当たっていないことが分かりました。028 と 029 の更新が当たらないまま、その次の 030 だけが当たっていたのです。
原因は、更新を当てる道具が、番号の順番を確かめていなかったことでした。順番の検査を足し、テスト環境のデータベースは元に戻しました。この記事は、何が起きたかと、再び起きないように足した「順番の検査」の記録です。
マイグレーションは、番号の順に当てるもの
アプリを作り進めると、データベースの形(表や列)を変える必要が出てきます。私たちは、その変更を1つずつファイルにし、先頭に3桁の番号を付けています。番号の順に当てていけば、どの環境でも同じ形のデータベースになります。

更新を当てる道具は、2つのものを見て動きます。
- 決まったフォルダにある、更新のファイルの一覧
- データベースに残している、「どのファイルを当てたか」の記録
フォルダにあって、まだ記録に無いファイルを、番号の順に当てていきます。
起きたこと

原因は、道具が「フォルダにあるもの」しか見ていなかったこと
更新の道具は、フォルダにあるファイルと、当てた記録しか見ていませんでした。もし、更新を流す時の作業のフォルダに、一部のファイルだけが置かれていたらどうなるでしょう。


順番の検査を足した
更新の道具に、当てる前の検査を2つ足しました。どちらかに当たったら、何も実行せずに止まります。試しに流すだけの時や、状態を表示するだけの時も、同じ検査をします。


// まだ当てていないのに、当てた中で一番新しいものより前の番号がある
$latest = max($appliedNames);
$earlier = array_filter($pendingNames, fn ($n) => strcmp($n, $latest) < 0);
// フォルダにも、当てた記録にも無い番号がある
$known = [];
foreach ([...$appliedNames, ...$fileNames] as $n) {
$known[(int) substr($n, 0, 3)] = true;
}
$missing = [];
for ($i = min(array_keys($known)); $i <= max(array_keys($known)); $i++) {
if (!isset($known[$i])) {
$missing[] = sprintf('%03d', $i);
}
}
if ($earlier || $missing) {
exit('マイグレーションは番号の順に、抜かさず当てる必要があります。何も実行していません');
}止まった時は、どの番号が先に必要かを表示します。「028・029 が先です」のように出るので、何をすればよいかがすぐに分かります。

本番に当てる時も、新しい道具を使う
本番のサーバーには、検査を足す前の古い道具が残っていました。本番の更新を流す手順では、サーバーの古い道具を使わず、検査の入った新しい道具と、すべての更新のファイルを、一時的な場所に送って使うようにしました。終わったら一時的な場所を消し、道具と接続の情報が残っていないことも確かめます。

まとめ

- テスト環境で、028 と 029 を飛ばして 030 だけが当たった
- 道具が、フォルダにあるファイルと当てた記録しか見ず、番号の抜けに気づけなかった
- 順番の崩れと番号の抜けを見つけたら、何も実行せずに止まる検査を足した
- 本番でも、検査の入った新しい道具を一時的に送って使う
この記事は、AI(Claude)の支援を受けて作成し、筆者が内容を確認しています。


