ドメイン駆動設計 (Domain-Driven Design, DDD)の概要
ドメイン駆動設計 (Domain-Driven Design, DDD) とは、ソフトウェア開発において、ビジネスドメインの理解に基づくソフトウェアの設計手法となる。
DDDでは、ソフトウェアの設計において、ビジネスドメインを中心に据え、ビジネス要件やビジネスプロセスを表現するための言葉や概念、ルール、制約条件などをモデル化する。これにより、開発者とドメインエキスパートが共通の言語を使用し、コミュニケーションを促進し、ビジネスニーズに応えるソフトウェアを実現することができるとされている。また、DDDでは、ソフトウェアを分割する際に、ドメインモデルに基づく分割方法を採用することが推奨されており、このアプローチにより、ソフトウェアの各層がドメインモデルに従い、一貫性のある設計が実現されるともされている。
DDDは、エンタープライズアプリケーションや複雑なドメインモデルを持つソフトウェアの開発に有効な手法とされているが、学習コストや導入コストがかかるため、必ずしもすべてのプロジェクトに適しているわけではない。ただし、”マイクロサービスのアーキテクチャの概要“で述べているように、アプリケーションを小さなサービスに分割し、各サービスが独立して実行できるようにするアーキテクチャのスタイルであるマイクロサービスにおいて、異なるレベルの抽象化であるが、相互に補完的な手法として使用できることが述べられている。
これは、マイクロサービスアーキテクチャにおいて、DDDを使用することで、各サービスが独自のドメインに焦点を当て、他のサービスとの結合度を最小限に抑えることができ、また、DDDによって、ドメインモデルがより明確に定義されるため、各サービスが正確なデータとロジックを処理することができること。
また、マイクロサービスアーキテクチャは、DDDによって定義されたドメインモデルを各サービスに分割することができるため、各サービスが自己完結型で、単一の大規模なアプリケーションよりもはるかに柔軟性が高くなり、更に、各サービスを独立してスケーリングすることができるため、アプリケーションのパフォーマンスと可用性が向上するということにあたる。
DDDでのソフトウェア開発の流れ
DDDにおいて、ソフトウェアの開発には、以下のような一般的な流れがある。
- ドメインの理解: ソフトウェアの目的やビジネス上の課題を理解し、ドメインに関する知識を習得する。このプロセスでは、ビジネスエキスパートやステークホルダーとの対話が重要であり、この段階では、ドメインに関する用語や概念を特定し、これらをモデル化するための言語を選択することとなる。
- モデルの作成: ドメインの知識をもとに、ドメインモデルを作成する。モデル化のために使用する言語は、ビジネス用語に応じて自由に選択でき、この段階で、モデルをドキュメント化し、モデルが正しいかどうかを確認することができる。
- ユビキタス言語の確立: モデル化のために使用する言語は、ユビキタス言語としてドメイン内で共有される。ユビキタス言語は、ビジネス用語を技術用語と結びつけるためのもので、開発者とドメインエキスパートが共通の言語を使用し、コミュニケーションを円滑にすることができる。
- アーキテクチャの設計: モデルをもとに、システムのアーキテクチャを設計する。この段階では、モデルを分析し、ドメインの異なる側面を分離するために、複数のサブドメインに分割する。また、リポジトリやファクトリ、サービスなどのドメインオブジェクトを設計し、モデルの一貫性を確保する。
- 実装とテスト: アーキテクチャの設計に基づいて、実際のコードを書きます。このプロセスでは、ドメインオブジェクトを実装し、リポジトリやファクトリ、サービスなどを使用して、ドメインモデルを実現する。また、テストを書き、コードが正しく動作することを確認する。
- 継続的な改善: システムが実際に使用されるにつれて、新しいビジネス要件が浮上し、ドメインモデルが変化することがある。このため、システムを継続的に改善することが必要となる。
DDDが適用されるアプケーション例
DDDは、ビジネスロジックが複雑であるような、大規模かつ複雑なソフトウェアシステムの開発に主に適用される。以下は、DDDが適用される可能性があるアプリケーションの例となる。
- 銀行や保険会社のシステム
- オンラインストアやマーケットプレイスのシステム
- 医療機関の電子カルテシステム
- 輸送業や物流業のシステム
- 航空会社や鉄道会社のシステム
- IoTデバイスやスマートホームシステム
これらのアプリケーションは、多くの場合、複雑なドメイン知識を必要とし、ビジネスプロセスが複雑であり、また、複数のサブドメインを持つ。DDDは、これらの問題に対応するために設計されており、ドメインモデルとユビキタス言語を中心にアプリケーションを構築することで、開発者とビジネスエキスパートのコミュニケーションを改善し、ソフトウェアの保守性と拡張性を高めることができる。
DDDとAIアプリケーションとの関係
DDDとAIアプリケーションの関係については、いくつかの観点から関連性を考えることができる。
まず、DDDは、ドメイン知識を中心にアプリケーションを構築するためのアーキテクチャパターンとなる。AIアプリケーションでも、ドメイン知識を適切にモデル化することが重要で、例えば、画像認識や音声認識などのAI技術を利用する場合は、ドメイン知識に応じたモデルを作成する必要がある。このように、AIアプリケーションでもDDDのアーキテクチャパターンを適用することができる。
また、DDDでは、ユビキタス言語を用いてドメイン知識を共有することが重要であり、AIアプリケーションでも同様に、ビジネスエキスパートやAIエンジニア、データサイエンティストなど、様々なバックグラウンドを持つ人々が共通の言語を用いてコミュニケーションを行うことが必要となる。
さらに、AIアプリケーションでは、モデルの設計やデータの前処理など、ドメイン知識に基づいた意思決定が必要となる。DDDのアーキテクチャは、ドメイン知識を適切にモデル化することで、このような意思決定をサポートすることができる。
参考図書
DDDの参考図書として著名なものとして「エリック・エヴァンスのドメイン駆動設計」や「実践ドメイン駆動設計」等がある。
エリック・エヴァンスのドメイン駆動設計は「Domain-Driven Design: Tackling Complexity in the Heart of Software」の翻訳で、ドメインモデルの設計手法について詳しく述べられているものとなる。
内容を以下に示す。
第1部 ドメインモデルを機能させる
ドメイン駆動設計におけるモデルの有用性
ソフトウェアの核心
第1章 知識をかみ砕く
効果的なモデリングの要素
知識のかみ砕き
継続的学習
知識豊富な設計
例1.1——隠された概念を引き出す
深いモデル
第2章 コミュニケーションと言語の使い方
ユビキタス言語(UBIQUITOUS LANGUAGE)
例2.1——貨物輸送プログラムを完成させる
声に出してモデリングする
1つのチームに1つの言語
ドキュメントと図
書かれた設計ドキュメント
実行可能な基盤
説明のためのモデル
例2.2——輸送業務と経路
第3章 モデルと実装を結びつける
モデル駆動設計(MODEL-DRIVEN DESIGN)
モデリングパラダイムとツールによるサポート
例3.1——手続き型からモデル駆動へ
骨格を見せる:なぜモデルがユーザにとって重要なのか?
実践的モデラ(HANDS ON MODELERS)
第2部 モデル駆動設計の構成要素
第4章 ドメインを隔離する
レイヤ化アーキテクチャ(LAYERED ARCHITECTURE)
例4.1——オンラインバンキングの機能をレイヤに分割する
レイヤを関係づける
アーキテクチャフレームワーク
ドメイン層はモデルが息づく場所
利口なUI「アンチパターン」(SMART UI メANTI-PATTERNモ)
その他の隔離
第5章 ソフトウェアで表現されたモデル
関連
例5.1——証券取引口座における関連
エンティティ(ENTITIES)(別名 参照オブジェクト(REFERENCE OBJECTS))
エンティティをモデル化する
同一性のための操作を設計する
値オブジェクト(VALUE OBJECTS)
値オブジェクトを設計する
例5.2——値オブジェクトを使ってデータベースをチューニングする
値オブジェクトを含む関連を設計する
サービス(SERVICES)
サービスと隔離されたドメイン層
粒度
サービスへのアクセス
モジュール(MODULES)(別名 パッケージ(PACKAGES))
アジャイルモジュール
例5.3——Javaにおけるパッケージのコーディング規約
インフラストラクチャ駆動パッケージングの落とし穴
モデリングパラダイム
なぜオブジェクトパラダイムが主流なのか?
オブジェクトの世界におけるオブジェクトではないもの
パラダイムを混在させる際にはモデル駆動設計に忠実であること
第6章 ドメインオブジェクトのライフサイクル
集約(AGGREGATES)
例6.1——購入注文の整合性
ファクトリ(FACTORIES)
ファクトリとその場所を選択する
コンストラクタがあればよい場合
インタフェースを設計する
不変条件のロジックはどこへ置くべきか?
エンティティファクトリ対値オブジェクトファクトリ
格納したオブジェクトを再構成する
リポジトリ(REPOSITORIES)
リポジトリに対して問い合わせる
クライアントのコードはリポジトリの実装を無視するが、開発者はそうではない
リポジトリを実装する
フレームワークの範囲内で作業する
ファクトリとの関係
関係データベースに合わせてオブジェクトを設計する
第7章 言語を使用する:応用例
貨物輸送システムを導入する
ドメインを隔離する:アプリケーションの導入
エンティティと値オブジェクトを区別する
役割とその他の属性
輸送ドメインの関連を設計する
集約の境界
リポジトリを選択する
シナリオをウォークスルーする
サンプルアプリケーションの機能:貨物の荷出し地を変更する
サンプルアプリケーションの機能:リピータへの対応
オブジェクトの生成
貨物用のファクトリとコンストラクタ
荷役イベントを追加する
リファクタリングのために立ち止まる:貨物集約についてのもう1つの設計
輸送モデルにおけるモジュール
新機能を導入する:配分チェック
2つのシステムを接続する
モデルを強化する:ビジネスのセグメント化
パフォーマンスチューニング
最後に
第3部 より深い洞察へ向かうリファクタリング
リファクタリングのレベル
深いモデル
深いモデル/しなやかな設計
発見のプロセス
第8章 ブレイクスルー
ブレイクスルーの話
悪くないモデルなのだが…
ブレイクスルー
さらに深いモデル
冷静な意思決定
結末
好機
基本への集中
エピローグ:新しい洞察の連鎖
第9章 暗黙的な概念を明示的にする
概念を掘り出す
言葉に耳を傾ける
例9.1——輸送モデルに欠けている概念を聞き分ける
ぎこちなさを精査する
例9.2——利息を得る 難しい方法
矛盾について熟考する
文献を読む
例9.3——利息を得る 文献を用いた場合
何度でも挑戦すること
それほど明白でない概念をモデル化する方法
明示的な制約
例9.4——再考:オーバーブッキングポリシー
ドメインオブジェクトとしてのプロセス
仕様(SPECIFICATION)
仕様の適用と実装
例9.5——化学製品倉庫での格納
例9.6——倉庫内格納サービスの、実際に動作するプロトタイプ
第10章 しなやかな設計
意図の明白なインタフェース(INTENTION-REVEALING INTERFACES)
例10.1——リファクタリング:塗料混合アプリケーション
副作用のない関数(SIDE-EFFECT-FREE-FUNCTIONS)
例10.2——リファクタリング:塗料混合アプリケーション再考
表明(ASSERTIONS)
例10.3——塗料の混合に戻る
概念の輪郭(CONCEPTUAL CONTOURS)
例10.4——発生の輪郭
独立したクラス(STANDALONE CLASSES)
閉じた操作(CLOSURE OF OPERATIONS)
例10.5——コレクションから選択する
宣言的な設計
ドメイン特化言語
設計の宣言的スタイル
宣言的スタイルで仕様を拡張する
例10.6——コンポジット仕様を実装する他の方法
攻める角度
サブドメインを切り取る
可能な場合には、確立された形式主義を活用する
例10.7——パターンを統合する:シェア算
第11章 アナリシスパターンを適用する
例11.1——利息を得る 勘定を用いた場合
例11.1(続き)——夜間バッチについての洞察
アナリシスパターンは活用すべき知識である
第12章 デザインパターンをモデルに関係づける
ストラテジー(STRATEGY)(別名 ポリシー(POLICY))
例12.1——経路検索ポリシー
コンポジット(COMPOSITE)
例12.2——経路で構成された輸送経路
なぜ、フライウェイトではないのか?
第13章 より深い洞察へ向かうリファクタリング
開始
探究チーム
先達の技
開発者のための設計
タイミング
好機となる危機
第4部 戦略的設計
第14章 モデルの整合性を維持する
境界づけられたコンテキスト(BOUNDED CONTEXT)
例14.1——予約コンテキスト
境界づけられたコンテキスト内での分派を認識する
継続的な統合(CONTINUOUS INTEGRATION)
コンテキストマップ(CONTEXT MAP)
例14.2——輸送アプリケーションにおける2つのコンテキスト
コンテキストの境界で行うテスト
コンテキストマップを構成してドキュメント化する
境界づけられたコンテキスト間の関係
共有カーネル(SHARED KARNEL)
顧客/供給者の開発チーム(CUSTOMER/SUPPLIER DEVELOPMENT TEAMS)
例14.3——収益分析と予約
順応者(CONFORMIST)
腐敗防止層(ANTICORRUPTION LAYER)
腐敗防止層のインタフェースを設計する
腐敗防止層を実装する
例14.4——レガシー予約アプリケーション
訓話
別々の道(SEPARATE WAYS)
例14.5——保険プロジェクトの縮小化
公開ホストサービス(OPEN HOST SERVICE)
公表された言語(PUBLISHED LANGUAGE)
例14.6——化学のための公表された言語
象のモデルを統一する
モデルコンテキスト戦略を選択する
チームでの意思決定と、より上層での意思決定
コンテキストに自らの身を置く
境界を変換する
変更できないものを受け入れる:外部システムの輪郭を描く
外部システムとの関係
設計中のシステム
別のモデルで特殊な要求を満たす
デプロイ
トレードオフ
すでにプロジェクトが進行中の場合
変換
コンテキストをマージする:別々の道 → 共有カーネル
コンテキストをマージする:共有カーネル → 継続的な統合
レガシーシステムを段階的に廃止する
公開ホストサービス → 公表された言語
第15章 蒸留
コアドメイン(CORE DOMAIN)
コアを選択する
誰がこの作業をやるのか?
蒸留の拡大
汎用サブドメイン(GENERIC SUBDOMAINS)
例15.1——2つのタイムゾーンの物語
汎用とは再利用可能という意味ではない
プロジェクトのリスク管理
ドメインビジョン声明文(DOMAIN VISION STATEMENT)
強調されたコア(HIGHLIGHTED CORE)
蒸留ドキュメント
コアにフラグを立てる
プロセスツールとしての蒸留ドキュメント
凝集されたメカニズム(COHESIVE MECHANISMS)
例15.2——組織図におけるメカニズム
汎用サブドメイン対凝集されたメカニズム
メカニズムがコアドメインの一部である場合
例15.3——一巡:組織図がメカニズムを再び吸収する
蒸留して宣言的スタイルにする
隔離されたコア(SEGREGATED CORE)
隔離されたコアを作成するコスト
チームの意思決定を進化させる
例15.4——貨物輸送モデルのコアを隔離する
抽象化されたコア(ABSTRACT CORE)
深いモデルの蒸留
リファクタリングの対象を選ぶ
第16章 大規模な構造
進化する秩序(EVOLVING ORDER)
システムのメタファ(SYSTEM METAPHOR)
「素朴なメタファ」とそれを必要としない理由
責務のレイヤ(RESPONSIBILITY LAYERS)
例16.1——深く掘り下げる:輸送システムをレイヤ化する
適切なレイヤを選択する
知識レベル(KNOWLEDGE LEVEL)
例16.2——従業員の給料と年金(1)
例16.3——従業員の給料と年金(2)知識レベル
着脱可能コンポーネントのフレームワーク(PLUGGABLE COMPONENT FRAMEWORK)
例16.4——SEMATECH CIMフレームワーク
構造による制約をどの程度厳しくするべきか?
ふさわしい構造へのリファクタリング
ミニマリズム
コミュニケーションと自己規律
再構成によってしなやかな設計がもたらされる
蒸留によって負荷が軽減される
第17章 戦略をまとめ上げる
大規模な構造と境界づけられたコンテキストを組み合わせる
大規模な構造と蒸留を組み合わせる
まず評価する
誰が戦略を策定するのか?
アプリケーション開発から現れる構造
顧客に焦点を合わせたアーキテクチャチーム
戦略的設計上の意思決定を行うために欠かせない6つのこと
同じことが技術的なフレームワークにも当てはまる
マスタプランに注意すること
結論
エピローグ
展望
付録 用語解説 参考文献 索引
実践ドメイン駆動設計は2003年に刊行された「エリック・エヴァンスのドメイン駆動設計」に対して、その後10年たった時点(2015年刊行)までに変化したコンピューティング環境の変化を踏まえて、コミュニティや実際のビジネスシーンのなかから実践的な方法論を精錬したものとなる。
以下にその内容を示す。
第1章 DDDへの誘い
第2章 ドメイン、サブドメイン、境界づけられたコンテキスト
第3章 コンテキストマップ
第4章 アーキテクチャ
第5章 エンティティ
第6章 値オブジェクト
第7章 サービス
第8章 ドメインイベント
第9章 モジュール
第10章 集約
第11章 ファクトリ
第12章 リポジトリ
第13章 境界づけられたコンテキストの結合
第14章 アプリケーション
コメント
[…] ドメイン駆動設計の概要とAIアプリケーションとの関係および参考図書 […]
[…] ドメイン駆動設計の概要とAIアプリケーションとの関係および参考図書 […]