ドメイン駆動設計とは?
高品質のソフトウェア設計をする手法、単純にバグがないと言うよりはビジネス的に成功していると言う意味合いが強い。「ユビキタス言語」と言うチーム共通言語でプログラムを実装する。
ドメインエキスパート
担当業務やシステムについて一番詳しい人のこと。担当職種に限らない(プログラマの場合もある。)し、複数人いる場合もある。
DDDを導入するメリット
- プログラマとドメインエキスパートが「共通言語」を用いて視点を合わせて一つのソフトウェアを構築できる。
- 業務知識をチームで洗練/共有して理解像を検討できる。
- 共通言語が設計となりコードとなる。(開発時の翻訳が不要になる。)
- ソフトウェア開発を「開発者視点」から「ビジネス視点」に変えることでビジネス価値、事業価値を高めることができる。
- UIやリクエスト単位で実装するのではなく、「ドメインモデル」で実装するのでUIやリクエストに依存した設計ではなくなるのでビジネスロジックが一元管理される。
ユビキタス言語とは?
ドメインエキスパートや開発者を含めたチーム全体で作り上げる共通言語のこと。
ユビキタス言語の見つけ方
レビューはチーム全体で行うのが望ましいです。
- ドメインに登場する用語について名称とアクションを記載する
- ユビキタス言語選定のために「用語集」を作成する。(困難な場合は作成済みのドキュメントから抜き出す。)
アジャイルを前提としている。
テストコードを先に書くテストファーストで実装が可能です。ドメインエキスパートはテストコードを見てユビキタス言語の認識が正しいかを確認できます。
概要図
View
ViewのコードをViewModelに移行させます。そして、ViewModelに対してテストコードを記述します。
View、ViewModel(画面と画面用ロジックが1:1)、InfrastructureやDomianのロジックを呼び出せます。
なので、ViewModelのテストを行うことによって自動的にInfrastructureやDomainのテストも行うことになります。
ViewModel
メンバー
Infrastracture(外部接続クラス)
DBなど外部と接続する必要がある場合にメンバとして定義します。
Domain層のインターフェース(Repository)を型として宣言し、コンストラクタでInfrastractureで定義したクラスを設定します。
フォームの入力値
各フォームのインプット要素をメンバとして定義します。言語によりますが、画面入力と同時に値が反映されるようにバインディングさせる設計にするのが望ましいです。
メソッド
View上のイベント処理
例えば、フォームの検索処理など。
DBなど外部アクセスが必要だった場合は、メンバで定義しておいた「Infrastracture(外部接続クラス)」などを使ってアクセスします。
基底クラス
BaseViewModelというクラスを作成して基底クラスを作るのが一般的です。
以下のどのViewModelでも共通して使用するような処理などはここに記載したりします。
- データバインディングする処理
Infrastructure
アプリの外部との接続部分(DBやファイル、ファイルなど)、Domain(主にインターフェイス)を参照します。外部との接続部分なのでここのコードはテストはしづらくなります。
テクノロジーごとに接続先のフォルダを作成します。何かbaseクラスに作法を書いておいて後は各クラスに実際に接続するソースを記述する。
- mysql
- s3
- csv
- xml
XXX(テクノロジー)Helper
テクノロジーに関係する文字列など(接続文字列)を記載します。(環境変数などに書いた方が良いか)
Domain:知識を表現するパターン(ドメインオブジェクト)
ビジネスロジック、ValueObject、Entitiy、Helper、Exception、静的ロジック、インターフェース(Repository)を記述します。どこも参照しない最上位のプロジェクトになります。
画面やDBなどアプリの外側に一切左右されない純粋なロジックを記述します。
ドメインの知識をオブジェクトとして表現するドメインオブジェクト等
値オブジェクト
ドメイン固有の概念を値として表現するパターン
エンティティ(Entities)
データベースのテーブルをかたどったクラスを入れます。
エンティティの命名規則
「テーブル名Entity」などと付ける。
ドメインサービス
「値オブジェクト」や「エンティティ」ではうまく表現できない知識を取り扱うためのパターン
ドメインオブジェクトを作成するメリット
コードのドキュメント性が高まる。
ドキュメントとコードがかけ離れてることは普通です。ドメインオブジェクトを作成しておくことでドキュメントがなくてもある程度仕様を把握することが可能になります。
テスト
テストコードです。
アプリケーションを実現するためのパターン
ドメインだけではアプリケーションとして成り立ちません。利用者の必要を満たすアプリケーションを構築する手法になります。
リポジトリ(Repositories)
データの保存や復元などを表すオブジェクト、Infrastractureのインターフェイスはここに記載します。
インターフェイスの命名規則
「Iテーブル名Repository」(IはインターフェイスのI)などとつけると良いでしょう。
アプリケーションサービス
アプリケーションそのもの。
ファクトリ
オブジェクトを作る知識に特化したオブジェクト
知識を表現する、より発展的なパターン
集約
値オブジェクトやエンティティなどのドメインオブジェクトを束ねて複雑なドメインを表現します。
仕様
モジュール
オブジェクトをまとめて管理する仕組みのこと。
Javaではパッケージ、C#では名前空間と呼ばれています。
モジュール名
1 |
組織名.コンテキスト名.Domain.model |
この中にエンティティ、値オブジェクト、ドメインサービスなどを格納していきます。
インターフェースを使う利点
クライアント側(フロントエンドなど)はインターフェイスを通じてアプリケーションサービスを呼び出します。
呼び出し方の例
- フロントとバックエンドが明確に言語なども分かれている場合は、APIのインターフェイス
- フロントとバックエンドが同じ言語の場合は、ViewModelなどからの呼び出しのインターフェイス
利点
バックエンドの開発を待つ必要がない
クライアント側の開発者がモックオブジェクトを利用してプロダクション用の開発を進めることができます。
依存関係を減らせる。
例えば、ドメインサービスクラスからレポジトリを呼び出す際に、具象クラスを呼び出しているとレポジトリが変わった時に対応できなくなる。インターフェースを介して呼び出すことでレポジトリが変わった(例えば、RDBMS→NoSQLに変わってもドメインサービスクラスを書き直す必要がない。)ところでコードを書き直す必要がなくなる。
これは、SOLID原則の依存関係逆転の原則の利点そのものです。
また、本番環境はDBを使って、テストはテスト用のインメモリDBを使うなどのコードを書き分ける場合などにも役立ちます。
この記事へのコメントはありません。