データ、情報、データモデリングについて考える
json的なデータや、RDB等で外部キーをもって別のエンティティと繋がったデータについて、それをどうみなすのか、どうすべきなのか、といった曖昧なところで悩んでいたところを起点として考えているmiyamonz.icon
RDBにおける正規化というのは「何が一つなのか」というonenessの概念と言えそう
外部キーを持っていても、その参照先が変わってしまうと都合が悪い
イミュータブルなら値だし、ミュータブルなら値じゃない。
値はイミュータブルである。
値は意味論の観点から透過的である。
値の目的は
自分自身を曝すことで、比較と等値テストをしてもらえることにある。
何かをカプセル化してメソッドを提供して、何かをすることではない。
値は、「私を何かと比較してくれ。私は自分の正確な意味や意義を伝えるから」と言っているのである。値は文字列の外側のラベルに直接書いてある。
事実は変更できないので、値である
場所
もし何か自分が興味深いと思うものを見つけて、その情報を保持している場所の情報を相手に送ったとしたら、一体何を伝えたことになるだろう?何も伝えたことにならない!情報ではないことは確かだ、なぜなら、他の人がその場所を見に行ったときに、自分が見ていたのとは全く違う情報が保持されているかもしれないからだ。
逆もまたしかり、認識も同様である。もし自分が何かを認識する際、それが値であれば、時間をかけてそれを観察することができる。とくに、値のセットや、複合的な値の場合はとくに有用である。
住所は値か?miyamonz.icon
Aさんのある時点での住所、という意味なら、値
しかし、たとえば「近所のコインランドリー:〜〜」とメモしていたとしても、店が移転していたら使えない
その時点での住所、という意味なら値だが、
ポインタ的に使ってしまうと、
ポインタは数値として値ではあるが、
その先の情報は、時間で変化しうる
場所指向なプログラミングになってしまう
すなわち、そのデータが値であるかそうではないかは、その値の型が何であるかは厳密には関係がない
どんなにその型がスカラで、数値だったり文字列で
文字列型もちゃんとイミュータブルな言語であったとしても、
その数値をポインタと解釈したり認識して使うと、その先の情報はミュータブルである 文字列も、何かのキーとみなして扱ってしまうと、その先の情報がミュータブルかもしれない
RDBで正規化していても、外部キーに対するレコードがイミュータブル(insert only)になっていれば、
外部キーを値として扱えるし、参照先も値だから、relationをまとめて値にできる
このパラダイム・シフトが起こると、いろいろおもしろいことが起こる。その一つは、今メモリ上で行われているガーベージ・コレクションが、ストレージ層に対して行われるようになる。ディスク上に不要になった情報が残るようになるから。でも大丈夫。対処の方法をそのうち確立していくはずだ。
また今度ここも考えたいmiyamonz.icon
発生タイミングが異なるイベントを別テーブルに分けてる
ここでの外部キーでの分離は何を意味するか?
分離されているから、異なるタイミングで挿入できる
エンティティを分析して、エンティティイベントを見つけて、その単位で記録することで、シンプルにできるということだ
なぜそれによってシンプルにできるか、というところを掘り下げる
なぜバラバラにできるのか?
イベント間の外部キー参照ができるから
外部キー参照が安全であるのは、値という概念の性質がこれを保証している、というところが肝だろう
どう保証してるか
各々がイベント、事実であり、事実だからイミュータブルで、値である。
事実は、別の事実に対して、idなどで参照をしてる
このidは値である。参照先のレコードも事実で、値である
よって、このidを持っている参照元のレコードも、値になる
参照idが値であり、他のプロパティも値なら、値の集合である全体も値だからだ
どのように繋いでも、値であるがゆえに、情報を利用したり共有したりする際に、面倒事がない
だからこそ、参照idを持って、限界までバラバラに分解できる
単一の事実になるまで、小さくできる
個別の事実が小さいから、利用や、事実のinsertがしやすい
外部キー参照が安全であるのは、値という概念の性質がこれを保証している
この前提が崩れると不都合が起きる
前提が崩れるとは、
イベントの中に、何かミュータブルなエンティティへのidがあったら、おかしなことになる可能性がある
何が起こるか
情報の欠落とか
user created という事実がuserId だけを持ってても、その時点でそのユーザがどのような情報を持っていたかは、後で変更されてしまったら見えなくなる
じゃあ、システムで利用時に外部キーなどを元に結合してまとめて取る行為は何を意味するか?
RDBの設計とか、概念の設計レベルでは、onenessを考えたりすることで、互いの情報をどう表すのか検討するわけだが、
エンティティ間のリレーションを繋いだ形で情報を取得したい、ということも多い
プログラム上では、その方が利用しやすいからだ
概念レベルの設計が先にあり、でもそれらを結合してコード上では扱う、という二段構え的な考えでいいと思う
データ利用側、read側にとっては、いちいち都度クエリを投げるより、全部つながったjsonとしてデータを取り出せるほうが楽
じゃあ、システムで利用時にこれを結合してまとめて取る行為は何を意味するか?
これのこたえは、プログラマの都合がいいからそうしてるだけだろう
小さなエンティティを集めて関連付けて、システムを設計してる
なにかのアプリケーションコードは、一度にいくつかのエンティティを扱って、処理したり、UIでユーザに知恵供したりする
だから、そのいくつかのエンティティが繋がった形でデータが取れるのは良いことだ
単にSQLでjoinしたり、ORMやprisma等の賢いクエリビルダで、データを繋いだ形で利用できる事が多い
パフォーマンス的にも、一度にまとめて取る方がいい
ということがあり, read側はそういう形になるが
write側は、
イベント、事実単位で記録したり
というかたちで、read とwriteで型が異なる方が都合がいい
この分離をしない場合は、
型がテーブルのrecordとかでreadとwriteで共通になりがち
単にRDBのレコードを場所としてCRUDをしている
read とwrite時で扱う型が異なることは何を意味するか
CQRSってreducerじゃね?