テーブル設計: statusカラムから生じる技術的負債とその解決策①
概要
こういうテーブルを見たことはないだろうか。
statusごとに、nullable, not nullカラムが混在しているクレイジーなテーブルである。
どんなときに、値が入るねん!と不安にさせてくる。
どの現場にも存在して、もはや既視感すらある。
このテーブルの問題点とその解決案を説明していきたい。
登壇しました
対象読者
- テーブル設計を学んでいる方
- 技術的負債を解消したい方
いいね!してね
この記事の事例は必要に応じて今後追記していく予定です!
「新しい事例が知りたい」「他の事例も知りたい」と思った人は、ぜひこの記事にいいね👍してください。筆者のモチベーションにつながります!
それでは以下が本編です。
結論
✅テーブルに状態を持たせない(statusカラムをつけない)、ロングタームイベントパターンでテーブルを分割する。
テーブルの数は多いけど、シンプルで可読性が高い
解説は別記事
説明すること
- statusカラムの問題点
- 解決案
statusカラムの問題点
❌テーブルにnullableなカラムが混在してしまう
カラムの値を参照する前に、まずstatusを参照して条件を分岐する
その後に値のnullチェックをしながらロジックをつくる。
↓
そして、クソコードとの戦いが始まる、、!
エンジニアとして様々な案件にjoinしてきた。
アプリケーションの設計以前にテーブル設計がおかしいケースが多い。
statusカラムがあってそれに依存するカラムが別テーブルに切り出されている場合もほぼ同じぐらいキツかった。
同様の事例1: 削除フラグ
同様の事例2: クソコードUserクラス
❌履歴が残らない
「失敗から学ぶrdbの正しい歩き方」の「失われた事実」の章を読んでほしい。
この章では「状態を更新したら更新前のカラム値は消えてしまう」ことを指摘している。
※対応する履歴テーブルを作るのは面倒。できればやりたくない
解決案
再掲:解説は別記事
✅statusごとにテーブルを分ける
- テーブルに状態を持たせてはならない。
✅nullカラム, updatedAtを排除する
できるだけnot nullなカラムとする。
再度結論
✅テーブルに対応するルールや制約がシンプルにする
状態ごとにテーブルを分ける
テーブルごとに(バリデーションなどの)ロジックを切り出せる。
(原則)Not nullな値のみが存在する。
→ ロジックがシンプルになる。
✅テーブル運用がしやすい
テーブルのカラム数が少なくなる。
(原則)Not nullなのでindexが効きやすくなる。
※ステータスの変更量はそんなにないのでデータ量を心配しなくても良さそう(増えたら削除すればよい)
※粒度が細かすぎたら、テーブル統合できる(テーブル分離よりラクにできる)
✅履歴が残る
イベントを全てINSERTしてレコードを生成するため、履歴が残る。
「事実を残す」という目的を達成できる。
まとめ
「テーブルに状態を持たせるな!」と言うが、
「じゃあどうすればいいねん?」と思っていた。
その疑問に対する答えが出たので記事にした!
この記事が参考になった方は、ぜひこの記事にいいね👍してください。筆者のモチベーションにつながります!
引用
ミノ駆動さんの「クソコード動画「Userクラス」で考える技術的負債解消の観点」:
曽根壮大さんの「失敗から学ぶrdbの正しい歩き方」:
kawasimaさんの「イミュータブルデータモデル」:
Discussion
こういうのみたら勉強になるかもって教えていただいたリンクを貼っておきます