CBcloud Advent Calender 7日目の記事です。
CBcloudでは、ドメイン駆動設計を明確に推進しているわけではないですが、物流に関する様々な業務フローや業務知識に触れてきたことでそれらを全社的にまとめあげる必要があると個人的に感じており、エリック・エヴァンスのドメイン駆動設計(日本語訳版)を読み直しています。
本書では概念的な説明が多いために、ドメイン駆動設計に登場する概念を正確に理解して、概念同士の関連やその文章内の言葉がどの概念を指しているのかを強く意識しておかないと何を言っているのかよくわからない、ということになりそうだと感じました。
そこで、本記事では、エリック・エヴァンスのドメイン駆動設計に登場する概念の説明と書籍内での用語について解説し、初めて本書を読む人がスムーズに読み進められるようになることを目指します。
- その1: ドメインモデル(この記事)
- その2: しなやかな設計
- その3: モデルの整合性を保つためのパターン
概念図
いきなりですが、各用語が指す関係について私の理解を図にしました。この図を元に解説をしていきます。
「ドメイン」「モデル」の意味
本書では、「モデル」「ドメイン」という言葉や、さらには「ドメインモデル」「ドメインオブジェクト」といった言葉も出てきます。それらの違いについて説明します。
ドメイン
システム化の対象範囲となる業務に関する知識のこと。あるいは、レイヤ化アーキテクチャ(後述)で分けられた層の一つ。「業務知識」と読み替えると良いかもしれません。
モデル
業務知識を整理して抽象化・構造化した概念のこと。モデルが表現する範囲は、レイヤー化アーキテクチャのドメイン層内です。書籍内ではモデルを表現するときにUMLに似た図が用いられますが、「図=モデル」ではなく、図はモデルについてコミュニケーションするためのツールにすぎません。そのため、図に決まったフォーマットはありません。また、モデルは複数存在することもあります。モデルは1つのクラスファイルというわけでもないので、何を単位にモデルを1つとしてカウントするかというと、「境界づけられたコンテキスト」によって区切られた単位で1つとしてカウントします。
派生
上記を前提としてそれらを使った用語は下記のように解釈できると思います。
用語 | 説明 |
---|---|
ドメインモデル | モデルと同義。ドメインを表現するモデルだから、あるいは、ドメイン層に存在するモデルを指すからこのような表現になっているのかもしれません。 |
ドメインオブジェクト | モデルを表現するのに使われている、具体的なクラスやインスタンスを指す。後述する設計パターンのいずれかの概念に該当します。 |
ドメインエキスパート | システム化の対象である業務領域に知見のある人物。 |
ユビキタス言語
ドメインエキスパート、開発者などの役割を問わずチーム内で利用する共通の用語がユビキタス言語です。モデル内の概念は、このユビキタス言語で表現することでチーム内の認識を揃えます。
ドメインエキスパートが自分たちの専門用語を使うように、開発者も自分たちの専門用語を用いてコミュニケーションをしています。それだと、ドメインエキスパートの言う用語をシステムの用語に(頭の中あるいは会話の中で注釈を入れるなどして)翻訳してコミュニケーションしなければならないため、コストがかかり、認識の齟齬も生じます。
ユビキタス言語はモデルを表現する語彙であるため、その語彙を使ってコミュニケーションしていると、議論しにくいとか、意図が伝わりにくいといったモデルの不自然な部分が見つかるようになります。これによってモデルを改善する機会が生まれます。
モデル駆動設計
本書でも「ドメイン駆動設計」ではなく「モデル駆動設計」という言葉が登場してきて読んでいて戸惑いましたが、前述の「ドメイン」「モデル」の解釈に当てはめると、「ドメイン駆動設計」と異なる意味であることがわかりました。
「モデル駆動設計」は、ドメインから抽出したモデルと実際のコードを結びつける活動のことを指します。モデル駆動設計では、業務分析作業とソフトウェア設計作業の両方で使える単一のモデルを探し出すことを目的としています。
システムのコードはモデルを表現していなければなりません。そしてコードは変更されます。つまり、コードの変更はモデルへの変更にもなり得ます。それはモデルの変更を検討させ、モデルを改善することに繋がります。また、モデルはドメインの抽象化した概念であり、ユビキタス言語の基盤です。よってモデルは、分析と設計の両方で使えなければならないのです。
モデル駆動設計のパターン
優れたドメインモデルを構築することに体系的な手法は存在しません(本書内でも「芸術」と言っている)が、モデルの個々の要素をコードに落とし込むことはソフトウェアの設計原則を元にある程度体系立てて行うことができます。
下記は、本書内で紹介されている、モデル要素を設計・実装するためのパターンの一覧です。
個人的にはこれらはあくまでデザインパターンであり、ドメイン駆動設計に必要不可欠なものというわけではないと解釈しています(ドメイン駆動設計でなくてもこれらのパターンは利用可能なはず)。
パターン | 説明 |
---|---|
レイヤ化アーキテクチャ | プログラムをユーザインタフェース層、アプリケーション層、ドメイン層、インフラストラクチャ層のレイヤに分割する。各レイヤは下位レイヤにだけ依存する。これによりドメインモデルに関するコードを1つの層に集中させる。 |
関連 | 図だと要素同士をつなぐ線にあたる。オブジェクトを辿る方向を強制させる。 |
エンティティ(別名: 参照オブジェクト) | 他のオブジェクトと区別しなければならない(同一性を持つ)オブジェクト(例: 同姓同名のユーザオブジェクトでも区別できないといけない)。オブジェクトのライフサイクルと同一性の識別に集中する。 |
値オブジェクト | 同一性を持たないオブジェクト。モデル内における値を表現する(例: 住所オブジェクト。属性に県、市区町村、番地を持つが、誰の住所かは区別しない) |
サービス | ドメインの概念に関係しているが、エンティティや値オブジェクトの自然な一部ではない操作を定義する。操作名はユビキタス言語の一部であり、状態を持たず、引数と結果はドメインオブジェクトとなることが望ましい。 |
モジュール | コミュニケーションの仕組み。関連するオブジェクトを1つのモジュールに入れることで開発者にそれらをひとまとめに考えるよう伝えたり、「"顧客"モジュールについて話しましょう」とビジネスエキスパートに言うと会話の前提が整うような用途に耐えなければならない。モデルが物語とするとモジュールは章。 |
集約 | 関連するオブジェクトの集まり。データを変更するための単位。1つの集約には必ずルートと境界がある。ルートは集約の中の特定の1エンティティで、外部のオブジェクトが参照を保持ししてよい唯一のオブジェクト。境界は集約の内部に何があるかを定義する。 |
ファクトリ | 複雑なオブジェクトや集約のインスタンスを生成する。集約全体をひとまとまりとして生成し、その集約が守るべき不変条件を強制する。 |
リポジトリ | ファクトリが新しいオブジェクトの生成するのに対して、リポジトリは既存のオブジェクトを見つけ出す。DBへの接続処理等を隠蔽し、リポジトリの利用者にはオブジェクトがメモリ上にあると錯覚させる。DBから取得したデータを集約として組み立てるのにファクトリを利用することもある。 |
おわりに
だいぶ背景を省いているのでよくわからないところもあるかと思いますが、ドメインとモデルの意味と、エンティティや値オブジェクトなどは設計のパターンである、ということさえ理解できていれば大丈夫だと思います。
ドメイン駆動設計の理解の一助になれば幸いです。