はじめに
今年一番困ったこととして、
「ドメイン駆動開発について説明ができなかった。。。」
ということで、ドメイン駆動開発についてまとめてみたいと思います。
ドメイン駆動開発とは?
ドメイン駆動設計を元にアジャイル開発をしていくことを意味します。
ドメイン駆動設計とは?
ドメイン駆動設計(Domain Driven Design)
簡単にまとめると、
ドメイン知識を元に、各ドメインごとにモデルを作成していく設計手法。
利点
・ 各ドメインが独立した形になるため、膨大なプロジェクトの複雑さを取り除き、保守、運用が容易になる。
・ ドメインエキスパートと、開発者とのコミュニケーションが円滑になる。
※ドメインエキスパートとは:その専門領域に詳しい人。例)社員データのドメインエキスパートは、人事部。
ドメインって何?
domain
主な意味
領地、領土、(知識・思想・活動などの)領域、分野、…界、(土地の)完全所有権
各専門やサービスの担当領域を元に設計をするということですかね。
ドメイン駆動設計の手順
あくまで私なりに考えた手順なので、参考までに。
1. ストーリーを考える
-
何を作りたいか考える
例)リマインダーアプリを作りたい -
ストーリーを考える
設計の段階ではないので、ユーザー目線で書き出す。
例)
ユーザー視点で考えてみる。
1.ログインして、自分を認識してもらう。
2.リマインダーは一覧で見られる。
3.必要なリマインダーを新規で作る。
4.リマインダーには、年月日時分、タイトル、備考欄、タグを付けたい。
5.見たいリマインダーを検索する。
6.リマインダーを修正する。年月日時分、タイトル、備考欄、タグ、完了チェックが修正できる。
7.リマインダーを消すことができる。
8.タグは追加できる。タグには、色とタイトルが付けられる。
9.タグは編集できる。
9.タグは削除できる。
10.もし、リマインダー登録された年月日時分の該当時間になったら、Androidに通知される。
2. ユビキタス言語を作成する
ユビキタス言語: チーム全体(ドメインエキスパートや開発者)で作りあげる共通言語。
- 設計したいシステムのドメインに登場する用語についての名称とアクションを自由に書き出す。
- 用語集を作成して、用語に意味を定義する。さらに、それぞれのドメインに関連する用語をチェックしておく。
※のちにいらなくなるが、ここに書かれていない物はコードにも存在しないということが言える。
※もし必要なら、随時追加する。追加する場合は、ドメインエキスパートとディスカッションをして本当に必要か、同じような物はないか確認して追加する。
例)
ログイン:ユーザー認識するところ
ユーザー:アプリの利用者
リマインダー:指定された日付に、通知をしたい内容を持つ。年月日時分、タイトル、備考欄、タグ、完了チェックを持つ。
リマインダー一覧:今登録されているリマインダーを見られるところ
年月日時分: リマインダーに登録された、通知すべき日時。yyyyMMddhhmm(例:20201219)で構成。
完了チェック:リマインダーに登録されたスイッチ。通知すべき場合はTrue(ON)、通知しなくてもいいまたは完了の場合はFalse(OFF)。
タグ:リマインダーを分類する。色とタイトルを持つ。
通知:各リマインダーの年月日時分が該当時刻になったら、登録されたタイトルをAndroidアプリの通知機能で表示し、ユーザーに知らせる。
3. ユビキタス言語を元に、ドメインを定義する
元々のドメインの意味は: 領域。範囲
DDDのドメインの定義は、
-
ドメイン : チームが取り組む事業全体の枠。
そして、ドメインの中には3種類のドメインがある。
- コアドメイン : 業務的に最も重要で戦略的に不可欠。最優先。
-
支援サブドメイン : 業務的に特別なものだが、コアドメインほど最優先ではない。
(外部からプロジェクトを支える、外部ツールみたいなのとか) -
汎用サブドメイン : 特別ではないが、システムにおいては必要なもの。
(どこのシステムにも必要なものみたいな)
例)2で出したユビキタス言語を書き出して、ドメインに分割する。
-
コアドメイン: 今回のアプリケーションの場合、リマインダーを管理する部分がコアに当たるので、リマインダー管理に関連するもの
-
支援サブドメイン: 外部からリマインダーアプリを支える「通知」
-
汎用サブドメイン: ユーザー管理をするログイン業務は、システム的に必要なためこちら。
4. コンテキストマップを作成する
境界付けられたコンテキスト:ドメインという領域を、境界を付けて、分割することでシンプルにコンテキスト単位で管理できる。コンテキスト単位はチーム単位という認識になる。
例)
コンテキストマップ:コンテキスト間の関係を表す図。これを作成しておくことにより、チーム間でどのような連携を図るべきか計画を立てやすくなる。
5. 各コンテキストのアーキテクチャを考える
6. ドメイン、コンテキストマップ、アーキテクチャを元に、ソースコードに落とし込む。
例)
コアコンテキスト(リマインダー管理ドメイン)のプロジェクト構成。
remainderManager
├── application
│ ├── api #Restで外部とデータの受け渡しができる。UIとのデータのやりとりに使う。
│ ├── dpo #複数の集約データを取得して、詰め替えた値を持つ入れ物
│ ├── dto #複数の集約インスタンスの参照をプロパティにて持つ入れ物
│ └── service #domain層のセパレートインターフェイスを介して、集約を取得し、dtoやdpoに変換したりするロジック。
├── domain
│ ├── factory #集約のルートとして実装。他のコンテキスト間とのやりとりを担う。
│ ├── aggregation #集約。オブジェクト(entityや値オブジェクト)のまとまりを表す。
│ ├── entity #一意なものを表現する概念。オブジェクト。ストーリーで書いたときの「変更」や「登録」等の動詞の主語に当たる部分が該当
│ └── service #ドメインオブジェクトの外に記述した方が良いロジックの部分。infrastracture層のセパレートインターフェイスを介して、データを取り出して加工したりする。
└── infrastructure
├── model #DBのデータを受け渡しするための入れ物。
└── repository #DBからデータを追加、取得、更新、削除する。
※セパレートインターフェイス:実装クラスとは別の層にインターフェイスを宣言することで、依存関係をシンプルにする。
7. モジュールの構成
1ドメインで1モジュール作成する。
各コアコンテキスト、サブコンテキストは、サブモジュールとしてモジュールに含める。
例)
# モジュール名
remainder
# 認証・アクセスコンテキスト
remainder.identityAccess.application
remainder.identityAccess.domain
remainder.identityAccess.infrastructure
# リマインダー通知コンテキスト
remainder.notification.application
remainder.notification.domain
remainder.notification.infrastructure
# リマインダー管理コンテキスト
remainder.notification.application
remainder.notification.domain
remainder.notification.infrastructure
終わりに
ドメイン駆動設計は、
業務ごとに分けられているため、それぞれが疎結合になっていて、保守の際にお互いのクラスに大きな影響が出なさそうなのは便利だなと思いました。追加機能を実装するときも便利そうですね
でも、一つ一つDBアクセスから受け渡しからロジックからが別々にあるので、実装には手間がかかりそうで...
どこかの記事に、コスト面が...と書いてあったのもよくわかりました。
コスト面をとるか、複雑化しやすい大きなプロジェクトの保守のしやすさを重視するか悩みますね。
参照
IDDD本から理解する
https://codezine.jp/article/corner/655
境界づけられたコンテキスト 概念編
https://little-hands.hatenablog.com/entry/2017/11/28/bouded-context-concept
DDDのドメイン・サブドメイン・ユビキタス言語・境界づけられたコンテキストを整理する
https://qiita.com/crossroad0201/items/875c5f76ed3794ed56c4
ドメイン駆動設計は何を解決しようとしているのか[DDD]
https://qiita.com/little_hand_s/items/721afcbc555444663247