既存の一括更新処理へ新しい制約チェックを後付けする時は、今回更新したフィールドに関与する制約だけを評価し、無関係な過去の違反を巻き込まない
バックエンド
設計判断
データマイグレーション
判断
稼働中の一括更新(bulk update)処理に、新しい業務ルール違反の検出を後付けするとき、対象レコード全体に対して無条件に制約を評価すると、今回のリクエストとは無関係な既存データの制約違反(過去の仕様変更やデータ移行で生じた不整合)まで検出してしまい、本来成功するはずの更新まで一括で失敗・スキップ対象にしてしまう。
判断基準
- 「今回のリクエストが新しく引き起こす違反」だけを検出対象にする。評価対象の制約は、今回更新しようとしているフィールド(更新パラメータに含まれるフィールド)が、その制約の「対象(ターゲット)」または「条件(トリガーとなる項目)」のどちらかに関与している場合に限定する。どちらにも関与しない制約は、たとえ現在の状態が違反していても評価しない。
- 双方向性のある制約(AとBが互いに影響し合う関係)では、更新後の状態を使って両方向を1本の判定でカバーできる。Aが更新された場合もBが更新された場合も、「更新後のAの値」と「更新後のBの値」の組み合わせだけを見れば整合性は判定できる。
- 制約評価は、更新前の値ではなく更新適用後の状態に対して行う。更新処理が対象エンティティの状態をその場で書き換える実装なら、書き換え後・永続化前のタイミングで評価するのが自然な差し込み位置になる。
なぜ
新しい制約は多くの場合、機能追加時点より前から存在するデータには適用されていない。後付けの制約チェックを「常に全件評価」にすると、機能追加前からの不整合データを持つレコードが、今回のリクエストとは無関係の理由で軒並み失敗・スキップされる後方互換性の破壊が起きる。「関与するフィールドが今回のリクエストで変更対象になっているか」で評価対象を絞ることで、後方互換性を保ちながら新しい違反だけを取り締まれる。
検証方法
(1) 制約の対象フィールドが更新対象に含まれ、かつ更新後の値が制約に違反するケースで検出されること、(2) 制約に無関係なフィールドだけを更新するとき、対象レコードの他のフィールドが既に(今回の変更と無関係に)制約違反の状態であっても検出されないこと、の両方をテストする。(2)を書き忘れると、後方互換性破壊に気づかないまま実装が完了したと誤認しやすい。