/note/tech

なぜステータスが混在するテーブル設計が生まれるのか

要約:

■ 1. 概要

  • 業務システムのDBに複数のステータスカラムが混在するテーブル設計が生まれる原因と防止策を解説する
  • 問題の根本はイベントとリソースを区別しないまま設計を始めることにある

■ 2. ステータス混在テーブルが生まれる原因

  • イベントとリソースを区別せずに設計している:
    • リソースとは現在の状態を表す「物」であり、イベントとは「何かが起きた」という事実の記録である
    • ステータスはイベントの移り変わりを現在の視点から表したものである
    • この認識がないとステータス変化をUPDATEで上書きする問題として捉え、管理したいカラムを一つのテーブルに追加し続ける結果になる
  • カラム定義から設計を始めている:
    • 「何を保存したいか」から設計を始めると保存したいものをすべてカラムとして並べることになる
    • 本来の順番は逆であり「このシステムでどんなイベントが起きるか」を先に列挙してから「イベントの結果として何がリソースとして残るか」を決める
  • 外部システムの仕様をそのままDBに持ち込んでいる:
    • 外部コードは数値の飛び番・機関ごとの差異・外部都合の値など自社の業務ステータスとは異質な特徴を持つ
    • 内部ステータスと同テーブルに混在させると自社業務ステータスと外部コードの関係が定義されず、外部仕様変更時の修正箇所の特定が困難になる
  • 連携元システムの設計を無批判に踏襲している:
    • 外部システムのDBをクローンして区分値テーブルなしに数値カラムだけを持ち込むと値の意味が自社コードベースのどこにも存在しない状態になる
    • この状態でスキーマを継ぎ足すと同じパターンのカラムが作られ続ける

■ 3. 防止するための設計手順

  • イベントを先に列挙する:
    • テーブルやカラムを考える前に「このシステムで何が起きるか」を書き出す
    • イベントを列挙することでテーブルの責務が明確になる
  • リソースとイベント記録を分離する:
    • リソーステーブルは現在の状態を表しUPDATEが発生する
    • イベントテーブルは発生した事実を記録しINSERTのみを原則とする
    • 外部コードは外部イベントテーブルに生データとして保持し、自社ビジネス判断を表す内部ステータスは別カラムで管理する
  • ステータス遷移を先に定義する:
    • リソーステーブルにステータスカラムを置く前に遷移図を作成する
    • 遷移図により「どの遷移で何のカラムを更新するか」「どの遷移は許可されないか」「どの遷移にイベント記録が必要か」が自然に決まる
  • 外部コードと内部ステータスを分ける:
    • 外部コード(生データ)はイベントテーブルにVARCHARまたは元の型で保持し変換しない
    • 内部ステータスはリソーステーブルにTINYINT+Enum定数で管理し受信時に変換する
    • この設計により外部仕様が変わってもマッピング処理だけを変えればよい状態になる
  • 外部の区分値を持ち込む際は意味も一緒に持ち込む:
    • 区分値テーブルもクローンして自社アプリから参照できるようにする
    • またはクローン時点で自社の定数・Enumにマッピングして変換する
    • どちらも取らないまま数値だけを引き継ぐと値の意味が自社システム内のどこにも存在しなくなる

■ 4. まとめ

  • ステータス混在テーブルの問題はコードを書き始めてから気づくことが多い
  • 根本原因はほぼ常に設計の最初にイベントとリソースを区別できていなかったことにある