← 記事一覧に戻る
テクノロジー

壊さずに変える、3段階のデータ・API変更術

壊さずに変える、3段階のデータ・API変更術

「カラム名を変えただけ」「必須項目を1つ足しただけ」。そんな小さな変更が、古いアプリの画面崩れや、処理中のジョブの失敗を引き起こすことがあります。この記事は設計工程の話です。データやAPIを変えるときに、一度に変えず3段階に分けて設計する方法を説明します。

なぜ一度に変えると壊れるのか

変更の瞬間、世の中には新旧が混在しています。

  • ストアの更新が済んでいない、古いバージョンのモバイルアプリ
  • 変更前のコードで積まれ、まだ実行されていないジョブ
  • ブラウザやCDNに残っている、古い形式のキャッシュ

これらは「デプロイした」だけでは消えません。設計の段階で新旧が混ざる期間を前提にしておく必要があります。

3段階で変える:expand / migrate / contract

1. expand(広げる)

新しい形を追加するだけで、古い形は消しません。カラム名をnameからdisplay_nameに変えるなら、まずdisplay_nameを追加します。書き込みは両方に行い、読み込みは新しい方を優先して、無ければ古い方を使います。

2. migrate(移す)

既存データを新しい形へ埋め直します。件数が多い場合は小分けにし、途中で止まっても再開できる作りにします。終わったら、移行前後の件数と欠損の数を照合します。

3. contract(縮める)

古い形を使うものが残っていないことを確認してから、古いカラムや古い項目を消します。この段階が一番危険なので、判断基準を先に決めておきます。

各段階で確認すること

  • expand:旧クライアントが、新しい項目を無視しても動くか
  • migrate:移行後の件数が、移行前と一致するか。やり直しても二重に書き込まないか
  • contract:旧クライアントの利用割合が十分に下がったか。読み書き両対応の期間は決めてあるか

目安の判断基準は、たとえば次のとおりです。「旧バージョンからのリクエストが、直近2週間で全体の1%未満」「両対応の期間は最低1リリースサイクル」。数字はサービスごとに決めてください。決めておくこと自体が重要です。

活用例:必須項目を足すAPIの変更

報告APIに、必須項目severityを足す場合を考えます。

// NG: 最初から必須にする
// 旧アプリは severity を送らないので、全リクエストが 422 になる

// OK: 3段階に分ける
// 1. expand : severity は任意。未指定なら "normal" として保存する
// 2. migrate: 既存データの severity を "normal" で埋める
// 3. contract: 旧バージョンの割合が下がってから必須にする

失敗例も1つ挙げます。カラム名を直接変えたところ、デプロイ前に積まれたジョブが古い名前で読み出し、静かに失敗し続けました。ジョブの待ち行列は、デプロイ前後で新旧が混ざる代表的な場所です。

設計時のチェックリスト

  • この変更を、1回のデプロイで完結させていないか
  • 新旧が混在する期間を、日数で書いてあるか
  • 古いクライアント・ジョブ・キャッシュの3つを洗い出したか
  • 消す判断を、数字で決めてあるか

Bugoon での実践

互換性の問題は、変更の直後に「あの画面が崩れた」という報告として現れます。Bugoon のウィジェットをサイトに埋め込んでおくと、報告にスクリーンショットと操作ステップ、ブラウザや画面サイズなどの環境情報が自動で付きます。iOS / Android アプリからの報告でも同様です。旧バージョンの利用者から報告が届いたとき、どの環境で起きたのかを往復なしで確かめられます。報告は GitHub Issue と連携でき、カンバンボードで contract 前の確認事項として管理することもできます。

チームのバグ報告を、もっとスムーズに。

Bugoon は無料で始められます。サイトにタグを 1 行追加するだけで、QA と開発の往復がなくなります。

無料で始める