見出し画像

【Javaでドメイン駆動設計を実現する-4】データベースの設計とドメインオブジェクトの関係について

これのつづき。

テーブル設計をすっきりさせて変更を容易にする

テーブル設計がごちゃごちゃしていると、「NULLが入ってきたらどうしよう」とか「イレギュラーな値が入っていた場合の対応は……」とか考えないといけなくて、結局プログラムもわちゃわちゃしてきてしまいます。

そこで、テーブル設計をスッキリさせて、変更を容易にしていきたいと思います。

テーブル設計をスッキリさせる、NotNull制約と一意性制約

まず、全てのテーブルからNullを排除することを目指します。各テーブル、全てNotNullに設定します。

「えー、でも、あとから入ってくる値とかあるし、今はNullしか入れられないじゃん?」

っていう時は、テーブルを分割して、その値だけ別のテーブルで管理するようにすることで、NotNullを守ることができます。

(……とはいえ、実際にプログラム作ってると宗教戦争が勃発したり、古いシステムからの移行で躓いたり、時間の制約があったり、なかなか思うようには行かないわけですが…………)

さらに、各行を一意にし、重複するデータが入らないようにすることでデータベースは綺麗に保たれます。

重複するデータって、本来必要ないですもんね。

仮に、ある人物がサービスへ入会→退会→再入会を繰り返して、入会記録に「該当者の名前、住所、年齢、電話番号……等が完全一致」するデータがあったとしても、絶対に入会日が違って、全く同じ入会記録は2行にはならないはずです。

外部制約キーで整合性を保つ

そうやってテーブルを分割分割していると、どのデータとどのデータがどう結びついていたのかが解らなくなってしまいます。

そこで、外部制約キーを使って、「このテーブルにあるものしかこっちのテーブルに入れられないよ」と制限して、データの整合性を保ちます。

データベースは「コト」の記録を中心に

actionとかリレキとか呼ばれるやつですね。

起きたことを正確に記録することを優先します。起きたことを「全て」記録するので、例えば何か修正があったとしても、UPDATEは使わず、取り消しデータも記録して、さらに新しいデータを記録します。これで変更の記録も残ります。

そして、現在の状態は履歴を集計して求めればよいのです。

……とはいえ、例えば残高を導出するのに毎回毎回全ての履歴をさらって計算していてはアプリケーションが激重になってしまうので、現在の状態(=ステータス)を別テーブルに持つようにするのが現実的です。

ただし、ステータスの更新は厳密な即時性が求められることは少ないので、「ステータスの更新が失敗したら履歴の登録も巻き戻す」というのは設計としてあまりよくなく、履歴を登録→別途ステータスを更新、という流れにする方が実用的です。

で、そんなときには非同期メッセージングの仕組みが役に立ちます。履歴を登録したらメッセージが飛んで、ステータス更新の仕組みが動く、というわけです。

オブジェクトはオブジェクトらしく、テーブルはテーブルらしく作って紐付ける

テーブルを適切に分割していくと、オブジェクトの持つフィールド変数とテーブルの構成が似てくるはずです。

でも、全く同一にはならないこともチョコチョコ出てくるはず。なので、JPAみたいに「オブジェクトの宣言を流用してそのままテーブル作っちゃえ~」とか、逆に「テーブル設計の通りにオブジェクトを作ろう~」とかやってしまうと、細かい部分で無理が発生してきます。

なので、オブジェクトはオブジェクトらしく、テーブルはテーブルらしく作った上で、どのオブジェクトの持つ情報と、どのテーブルのどのカラムに入っている情報とを紐付けるのか、適切なマッピングが求められます。

その辺の具体的な実装にはByBatisっていうフレームワークが良いそうなのでそれは別途お勉強することになります。今は概念だけ。

続きはこちら。


この記事が気に入ったらサポートをしてみませんか?