質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.51%
ドメイン駆動設計

ドメイン駆動設計(Domain-driven design, DDD)とは、ソフトウェアの設計手法、および設計思想や哲学のことです。ドメインモデル構築の際に、設計上の判断を決定する枠組みとドメイン設計に関して議論するボキャブラリを提供するものです。

Q&A

1回答

926閲覧

データベースのレコードのIDはドメインの意味があるものとして、DDDのValueObjectの値として利用できますか?

unamu

総合スコア13

ドメイン駆動設計

ドメイン駆動設計(Domain-driven design, DDD)とは、ソフトウェアの設計手法、および設計思想や哲学のことです。ドメインモデル構築の際に、設計上の判断を決定する枠組みとドメイン設計に関して議論するボキャブラリを提供するものです。

0グッド

0クリップ

投稿2022/01/19 03:09

果物を表すValueObjectを書く必要があり。

すでに下記のDBレコードが存在すると仮定した場合。

果物テーブル

idname
1りんご
2みかん
3バナナ

出荷テーブル

idfruit_id(果物ID)volume(出荷個数)
1110
225
3320

ValueObject内の定数の定義は、下記のように名称で持つべきでしょうか?

php

1class Fruit { 2 const APPLE = 'りんご'; 3 const ORANGE = 'みかん'; 4 const BANANA = 'バナナ'; 5 ... 6}

もしくは、IDで持つべきでしょうか?

php

1class Fruit { 2 const APPLE = 1; 3 const ORANGE = 2; 4 const BANANA = 3; 5 ... 6}

私の考えでは、ドメインはDBの影響を受けないという原則があり、その観点で見ると
Entityの識別子は除外してIDはDBの都合の物であり、名称がドメインの本質だと考えますので、名称で持つべきだと思っています。

ですので、出荷Entityが下記のような場合で、Repositoryで永続化する場合にFruitを名称でもつと、IDへの変換を行う必要がありますが、
それもDDDを実践する上で必要なコストだと考えています。

php

1class Shipping { 2 private int $id; 3 private array $fruits; 4 private int $volume; 5 ... 6}

さらに、DBのid:3,name:バナナ が id:3,name:ばななに変更されても、
ValueObjectの const BANANA = 'バナナ'; を const BANANA = 'ばなな'; に変更は行ってはいけないと考えています、
DBの変更の影響を受けてValueObjectを変更する理由にはならないと考えている為です。
出荷Entity永続化のIDへの変換にて名称のズレが問題になりますが、それもインフラ層にて名称の変換を行い保存するべきと考えています。

しかし、データベースのレコードIDをドメインの意味があるものとして捉えれると考えた場合は、これらの変換対応コストが不要になります。

果物テーブルのIDはドメインとして意味があるものでしょうか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

DDDには「IDを生の数字や文字列で扱うべきではない」と解釈できる指針(ValueObjectがそうです)はありますが、DB都合のIDをドメインで扱ってはいけないという話はないと思います。

IDはたしかにDBの都合ではありますが、この影響がアプリケーションに出るのを許容しなければままならないです。Id=Identifier=識別子 ですから個体識別に用いるのはむしろ自然です。

Idはアプリにおいて自然に扱える。その上で、DBのテーブル上で表現されるID(数値や文字列といった「生の値」)を、アプリ側においては明示的な型として表現することでDB都合の値をアプリケーションで「安全に」扱えるようにしよう、という取り組みがDDDの考え方の一つだと思います。

例えば、果物テーブルのIdをint型ではなく FruitId型 で表現すると、GetFruit(int) ではなく GetFruit(FruitId) と表せます。リテラルな型を避けることで対応する引数の値を少ない検証コードで用いることが出来るのではないでしょうか。依然としてnew FruitId(0) といったダーティな書き方で回避することは出来てしまいますが、こう書いたらダメだろうなとわかる「臭うコード」になっていると思います。

一方で、ValueObjectとして値に型を与える設計のインパクトがより出てくるのは、おそらくこの後の金額計算といった異なる単位の計算が出てきたところになります。

例えば、金額や税率を含む計算を行う際は、単位の異なる数値の加減乗除が行われますが、ある単位同士の演算を予め定義しておくことで「税率を含む金額の値型に更に税率を掛けてしまう」といったミスをコンパイル段階で検知し修正することが出来ます。

まとめると、DB都合のIdはアプリ側で扱って問題ありませんが、DB都合の数値や文字列といった生の値がアプリケーションコードの中で流通しないようになるたけ型でラッピングすると比較的安全に扱えます。

最後に、名称変更の実装についてですが、実務的にはデータベースが主のデータとなるようにするんじゃないかと思います。アプリ側にもデータベースと同じようなデータ(果物名の定数)を冗長に持たせることは、まさしく冗長で無駄な繰り返しと思います。質問の例においては「果物名はFruitIdを使って果物テーブルに問い合わせて解決する」という一つのルートに絞ることで設計としてもコンパクトにまとまるんじゃないかと思います。

参考

型を活用したプログラミング
https://zenn.dev/m_takehara/articles/351624df648ce9cb0ed0

投稿2022/01/20 13:11

編集2022/01/20 13:13
tor4kichi

総合スコア763

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.51%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問