はじめに
ドメインモデルをモデリングする上で、これってこのドメインに入れればいいんだっけ?このドメインってこれでいいんだっけ。あいつどのドメインにいるんだっけ?ってなると思います。
そこで自分用にドメインモデリングする際に必要な思考を纏めて、言語化してみます。
また筆者自身は現在DDDを学習中の身であり、まだまだ未熟ですのでもし内容が間違っている、補足、追記がある場合はコメント又は編集リクエストを頂けたらと思います!
ドメインとは
実践DDDの9章でコード上でドメインと呼ぶか、ドメインモデルと呼ぶかの考察の部分から抜粋
ドメインは、今取り組んでいる業務のノウハウの一面をとらえたものだ。私達が設計・実装するのは、ドメイン(業務)ではなく、ドメインのモデル(業務の仕組み、構造)である。つまり、結論としては、モデルをとりまとめるコンポーネント名(※言い換えてます)としては、ドメインと呼ぶよりドメインモデルのほうが適している。しかし、最終的に何と呼ぶかは、チームで決めることだ。
これはこうとも言いかえれます。
ドメインは、今取り組んでいる業務のノウハウの一面をとらえたものだ。私達が設計・実装するのは、業務ではなく、業務の仕組み、構造である。つまり、結論としては、モデルをとりまとめるコンポーネント名(※言い換えてます)としては、ドメインと呼ぶよりドメインモデルのほうが適している。しかし、最終的に何と呼ぶかは、チームで決めることだ。
まとめると、俺たちが議論してるのは特定ドメイン内のモデルの話だから、それはドメインモデルって名前で表現した方が正しいんじゃない?まぁ最終的にはチーム全体の意思が一番大切だから気に入らなかったら好きにしてくれ。
補足
業務とは、必ずしもソフトウェア開発者だけで考えるものではない。受託開発の場合はクライアントの場合だったり、また、会社の誰かがこんなのあったらもっと良いんじゃない?と新たな業務を提案する場合があります。そこから色々と議論がなされ、じゃあこうしよう!と最終的に新たな業務が誕生します。その業務が、ドメインです。そしてその業務の仕組みがドメインモデルです。
我々はその業務の仕組みをコードにそのまま反映させるだけです。(ユキビタス言語についてはあえてここでは紹介しない
反映させる時は永続化装置はどうするのかとか、そういった話はでません。そのようなインフラとかと繋がる部分は全てインターフェイスで表現することにより、余計な思考を頭から追い出し、より正確に業務内容・構造をコードで表現することができます。
1ドメインモデル、1リポジトリ・集約以下の原則
一応実践DDDの表9-1には、以下のように助言されている
モジュールは、モデリングの概念にフィットするように設計すべし
その理由
通常は、ひとつあるいはごく少数の凝集した集約ごとにひとるのモジュールを用意する。
しかし、複数の集約を1つのドメインで取り扱うとCCPとCRPに違反しがちになる。本当に違反しない凄い繊細な設計でも、メンテ大変そう。
なので、複数の集約を単一ドメインで持つのはやめとういたほうがいんじゃないかな。
ここから下の内容について
クリーンアーキテクチャのコンポーネントの原則に関する内容を纏めます。
このコンポーネントの原則は、DDDのドメインモデルをソフトウェアとして構築するのに役立ちます。
また、クリーンアーキテクチャのコンポーネントの原則のコンポーネントって何?どのコンポーネントの事?って思ってましたが、恐らくソフトウェアコンポーネントの事を指しているでしょう。コンポーネント指向で登場するコンポーネントと特徴が類似しています。
この前提知識の上に読み進めて頂けたらと思います。
閉鎖性共通の原則 (CCP)
これは単一責任の原則 (SRP)をコンポーネント向けに言い変えたものです。
クリーンアーキテクチャ本13章から抜粋
同じ理由、同じタイミングで変更されるクラスをコンポーネントにまとめること。変更の理由やタイミングが異なるクラスは、別のコンポーネントに分けること。
もう1つ抜粋
コンポーネントを変更する理由が複数あるべきだはない
あと1つ抜粋
同じタイミングで変更されることが多いクラスはひとつにまとめておけということだ。2つのクラスが物理的あるいは概念的に密結合していて、変更のタイニングがいつも一緒になるのであれば、それは同じコンポーネントに属するものだ。まとめておけば、ソフトウェアのリリースやデプロイの際の作業量を最小限に抑えられる。
解説
同じこと言いますが、1つのドメインモデルが変更される理由は複数あるべきではないって事ですね。
普通に このドメインモデル内に含まれるこのモジュールとこのモジュールって変更の理由全然違くない?って気づいたら、そのモジュールはもしかしたら他のドメインモデルのモジュールなのかもしれませんね。
また、本当は同じドメインモデルに入れるやつなんじゃないの?ってなったりする可能性もあるので、しっかり考察した上で最終判断をしたい所。
例
Aの業務に対して変更があったらAの業務を反映しているコードを修正するだけに留まらず、他のコンポーネントに属しているBを修正する必要がでた。
また、Bが表している業務に対して変更があった場合もAに影響があった場合、実はこの2つのコンポーネントって、同じコンポーネントのなんじゃない?だっていつも変更のタイミング同じだし、実は同じ業務だったけど、モデリングミスったんじゃない?って再考するタイミングだよねってこと。又は、単純にAコンポーネント内に配置していたとあるモジュールは実はBコンポーネントのものだったって事もありそうですね。
全再利用の原則 (CRP)
クリーンアーキテクチャ本13章から抜粋
コンポーネントのユーザーに対して、実際には使わないものへの依存を強要してはいけない。
もう1つ
全再利用の原則(CRP)ひとつのコンポーネントにまとめるべきクラスやモジュールを判断するための原則である。
あと1つ
わかりやすい例として、コンテナクラスとそれに対応するイテレータを考えてみよう。これらはまとめて再利用すべきものだ。お互いに密結合しているからである。したがって、これらは同じコンポーネントにまとめておくべきだ。
補足
この原則は、どのモジュール等を同じコンポーネントにまとめるかを教えてくれるが、それと同時にどのコンポーネントを同じコンポーネントにまとめてはいけないかを教えてくれてる。
まぁ、コンテナとイテレータの場合は、それらを使うAは別コンポーネントだよねとか。なぜなら、他のモジュールもコンテナとイテレータを使いたい場合、Aへの依存を強要してしまうからである。
再利用・リリース等価の原則 (REP)
クリーンアーキテクチャ本13章から一部抜粋
コンポーネントには一貫するテーマや目的があり、それを共有するモジュールを集めなければいけない。
解説
このテーマや目的がドメインモデル、業務を表現する、ですね。
その下にそのテーマや目的を共有する、リポジトリやファクトリ、エンティティ、etc...モジュール群がある感じです。
また、このコンポーネントはそれ単体でビルドが通せるかどうかも重要です。
最後に
本当はもっと沢山、色々と書きたかったんですが、それは自信もって "DDDちょっとできる" レベルになってからにしようと思います!