mike-neckのブログ

Java or Groovy or Swift or Golang

論理削除が云々について

今日朝イチで見たエントリーがこれでした。

qiita.com

論理削除の弊害は色々なところで言われているけど、僕の足りない頭で理解している所によると、二つの値しか持たない削除フラグ的なものはカーディナリティが云々で検索条件につけても性能上的にもよくないし、意味がないということです。

論理削除を完全に悪だとは言いませんが、論理削除を極力排したい人たちは、基本的にデータそのものを削除する、もしくは論理削除というのはまだ要件的に未確定な要素が隠されていることを示すフラグであると考えているようです。


僕がITの業界でキャリアをスタートしてから2年目くらいに配置されたプロジェクトではT字型ER手法というのをベースにしたテーブル設計をしていて、そこでかなり鍛えられたわけですが、その時にはだいたいこのような原則を叩きこまれました。

  • テーブルに状態を持たせない
  • 究極には機械が認識するキーと、人間にとって意味のあるデータだけのエンティティだけですべての業務のデータを構成できる
  • 日付を持つデータはイベント(これもひとつのエンティティ)
  • NULLのデータは絶対に持ってはならない
  • テーブルはでかく作るな、小さく作れ
  • テーブル同士の関連は直接持つな、関連を表すテーブルを作れ
  • 1:1の関連になったとしても、イベントとそれに付随するデータは分離しろ
  • データが増える?金と物理で殴れ(ディスク増強しろ)

その結果として、横7cm、縦5cmくらいで一つのエンティティを表しても、A0版用紙2枚にもなるER図をプロジェクトメンバー全員が所有するという状態になっていたわけですが…(テーブル数1600以上あったはず)

なお、そのプロジェクトでは論理削除は各テーブルにあって、それが元でバグを起こすなどの経験もしています。また、論理削除されたデータは当然他のテーブルから・へのリンクを含むわけで、どこまで削除されたデータを遡及して削除されたことにするのかということについて設計の段階で、かなり考慮する必要があったりします。


データの遡及に関しては論理削除だけではなく、DELETEされたデータに関しても当てはまると思っています。実際、上記に上げたQiitaのエントリーでも削除されたデータが参照されていた場合の対処方法について少しばかり言及されていたりします。

ただ、僕はその記事で取り上げられた例「社員が退職されたから削除」というのは例としてはよくないかなと思っています。その例では「社員」はマスターと言っていましたが、マスター(僕はリソースと呼んでいる)はシステムの開始から未来永劫追加・変更・削除することができないデータのことを指していて、「社員」というのはリソースではありえません。

「社員」というのは「社員」を雇わない会社がないことからわかるように、「社員」を雇うということによって新しいデータが発生するイベントデータ(人によってはトランと呼んでいるらしい、トランというのは僕はよくわからんけど)です。そして「社員」は皆さんがそうしているように、転職するとか、子会社の役員になるとか、定年退職されるとか、そういった「会社の所属から離れる」という次のイベントが発生するデータです。したがって、「社員」が論理削除される、削除されるということはありえないと考えています。だから、このエントリーはいいことを言っているんだけど、どうも理解しづらいと感じてしまったという印象を持ってしまったわけです。


まあ、人の揚げ足取りはやめにしておいて、何が言いたいかというと、論理削除にせよ、実際に削除するにせよ、すでにあるデータに対して何らかの操作をすることに何らかのきな臭さを感じているということです。僕がこれまた印象だけで碌に検証もせずに書いたエントリーで、UPDATE文は履歴系テーブルの扱いづらさを無視する操作だと書きました。

mike-neck.hatenadiary.com


このように考えるようになったのは、実はつい最近のことで、しょぼ勉に行けなかったので、先に上げた原則を振り返りつつ徹底していった時でした。削除にまつわるデータ設計の面倒臭さ(僕が思考停止)、データ更新時のアプリケーションにおけるoptimistic lockのあたりの実装の面倒臭さ(僕が思考停止)、削除データに由来するバグといった既存データに対する操作がもたらす悪影響などをずっと考えていました。で、至った結論が「CRUD」の「U」と「D」いらなくね?ということでした。


などということがあったなーと今日(2015/03/24)の夕刻のTLで削除フラグが云々となってて、

こういうお馬鹿なツイートをしている時に、

というツイートを見つけて、同じことを考えている人いるんだなと思った次第であります。

またDB-Fluteの作者さんのブログを読んでて(斜め読み)、データの削除は非推奨に辿り着いた時も、やっぱり「D」いらないよねとあらためて実感したわけです。

結論

議論が発散したし、論理的な根拠もないし、思考停止しているけど、言いたいことは、削除とか論理削除とかどうでもいいから、「CRUD」の「U」と「D」はやめろということです。


なお、異論は認めるし、反論も認める。テーブル数多すぎだって言う批判も認める。でも、テーブルで状態を持つな。状態を持たせたいなら別のテーブル作れ。JOINしたくない?じゃあ、お前はこれからコードを書くときにfilter/map/flatMap使うな。Nullableなデータがあるなら別のテーブル作れ。NULL三原則、作らず、持たず、持ち込ませずを守れ。特にトランザクションの激しいゲームにおいてはなおさら(ゲーム作るプロジェクトは嫌いですけどね)。

以上、あらためて異論、反論認める。


【2015/03/25 6:49追記】 ブックマークのコメント見てたら、二つの値でも片方が極端に少ない、片方が極端に多い場合は意味あるらしい(勉強になった)