この章で行うこと
- ドメイン駆動設計の概要を理解する
- ドメイン駆動設計を用いてアプリケーションを「設計」する
ドメイン駆動設計とは
その名の通り、「ドメイン」の知識に焦点を当てた設計手法です。
ソフトウェア開発におけるドメインは、「プログラムを適用する対象となる領域」を指します。重要なのはドメインが何かではなく、ドメインに含まれるものが何かです。
成瀬 允宣. ドメイン駆動設計入門 ボトムアップでわかる!ドメイン駆動設計の基本 (p.28). 株式会社翔泳社. Kindle 版.
プログラミングをして開発するそのアプリケーションが解決したい「課題」は利用者のドメインに存在します。問題解決をするための機能の「土台」に、ドメインは存在しています。つまり、問題を解決するには、まずドメインの概念・事象を理解し、知識を抽出する必要があるのです。
ドメインモデリング
ドメインモデルとは、「ドメインの概念をモデリングして得られるモデル」であり、ドメインの概念・事象を抽象化したものと言えます。まだぼやっとしていますね。
この抽出の作業をドメインモデリングといいます。
実際に、ドメインモデリングを簡単に行なってみましょう。洗い出したユースケース(機能)からユビキタス言語を策定し、ドメインモデルを抽出してみます。また、このドメインモデルをコードで表現したものをドメインオブジェクトといいます。以下の流れで簡易的にドメインモデリングを行ってみます。
- ユースケース洗い出し
- ユビキタス言語を抽出
- ドメインモデルを抽出
ユースケース洗い出し
今回は、「認証付きTODOアプリ(API)」を開発します。
機能としては以下のように洗い出せそうです。
- ユーザーはシステムに登録できる
- ユーザーはシステムを退会できる
- ユーザーはプロフィールを更新できる
- ユーザーはシステムに登録されているユーザーを一覧で取得できる
- ユーザーはタスクを作成できる
- ユーザーは自身の持つタスクを削除できる
- ユーザーは自身の持つタスクの状態を更新できる
- ユーザーはシステム上にあるタスク一覧を取得できる
- ユーザーはシステム上にあるタスクを指定して一つ取得できる
- ユーザーはユーザー自身が持つタスク一覧を取得できる
- ユーザーはシステムにログインできる
- ユーザーはシステムをログアウトできる
- システムは未ログインのユーザーの操作を禁止する
なお、これはあくまでこのハンズオンで扱うTODOアプリの機能一覧なので、「え、こんな機能いる?」「この機能いるでしょ!」っていうのは大目に見てもらえると助かります笑。本来ならば、他のユーザーのタスクやユーザー一覧を見る必要がなさそうですが、こういうケースならこう実装するかなぁという例として、盛り込んでみました(あくまで学習用途)。
ユビキタス言語
ユビキタス言語とは、ドメインの重要な概念を整理し、システム内での役割や振る舞いを明確に定義するためのものです。また、チーム内で齟齬などがないように、表現を統一した「共通言語」としての位置付けもあります。
| 用語 | 意味 |
|---|---|
| ユーザー | システムを利用する人。タスクを管理できる主体。 |
| ユーザープロフィール | ユーザーが持つパスワード以外の情報(メールアドレス・名前)。 |
| タスク | ユーザーが作成し、管理する具体的な作業単位。 |
| タスク内容 | タスクの内容。「golangを3時間勉強する」といった風の具体的な記述。 |
| タスク状態 | タスクの進行状況を示す状態(例:未完了、進行中、完了)。 |
| ユーザータスク | 特定のユーザーが保持しているタスクのみを指す。 |
ドメインモデルを抽出
ユーザー(User)
- 属性:識別子(id)・名前・メールアドレス・ハッシュ化済みパスワード
- ビジネスルール
- (登録・更新の際)同じメールアドレスを持つユーザーが重複してはいけない
- (登録の際)ハッシュ化される前の平文パスワードは6文字以上でなければならない
- (登録の際)メールアドレスは正しい形式でなければならない
- (認証の際)ハッシュ化済みパスワードと平文パスワードが一致しなければならない
タスク(Task)
- 属性:識別子(id)・ユーザーの識別子・内容・状態
- ビジネスルール
- (作成の際) 内容は空(0文字)ではいけない
- (作成・更新の際)不正なタスク状態を指定してはいけない
- 未完了・進行中・完了の3つのみ
- (更新・削除の際)タスクと紐づかないユーザーがタスクを操作できてはならない
また、ユーザーとタスクは「1対多」の関係があると言えそうですね。
認証はドメインか
認証系の扱いをドメイン知識とするかどうか迷いましたが、結論、ドメイン知識からは外れると判断しました。認証系は、技術的要件に分類されると思います。ドメインに存在していた概念ではなく、アプリケーションとして成立させるために後から必要になったものと捉えることができます。
このような判断理由で認証系はドメインからは外しておきました。「最上位レベルの方針か」と言われれば怪しいと筆者は思っています。
この辺の話はまた10章にて触れます。
参考記事
このように、ドメインモデルとしてユーザーとタスクを抽出しました。この二つは、エンティティとして表現されます。
エンティティ
エンティティとは、ドメインモデルを実装したドメインオブジェクトです。
以下のような性質を持っています。
- 同一性により区別される
- 識別子によって区別されます
- 同じ属性であっても区別される
- 例えば、同じ名前を持つユーザーが二人いても、メールアドレス or 識別子(id)が異なればそれは異なるユーザーとして区別できます
- 可変である
- これは可変であることが許可されているに過ぎず、可能な限り不変にしておきます
値オブジェクト
システムに登場する値をオブジェクトとして扱うための概念であり、ドメインオブジェクトです。プリミティブな文字列型ではなく、オブジェクトとして定義し、独自の振る舞いを持たせることができます。
値オブジェクトには
- 交換可能である 代入によってインスタンスを差し替えることで値の交換が可能です。
- 不変である 「交換(=代入)」以外で値を変更してはいけないということです。値を変更するような関数・メソッドを実装してはいけません。
- 等価性によって比較される 構成する属性によって比較されます。例えば、2つのメールアドレスオブジェクトのインスタンスがあったとして、おなじアドレスをそれぞれが有しているならば、それは等価であるとみなすことができます。
という性質があります。
属性を値オブジェクトとする基準
値オブジェクトとなる候補としては、ドメインモデル(オブジェクト)の属性があげられると思います。しかし、値を何でもかんでも値オブジェクトとする必要はありません。値オブジェクトとするかどうかの判断基準に関して、次のような言及があります。
ドメインモデルとして挙げられていなかった概念を値オブジェクトにすべきかどうかの判断基準として、筆者は「そこにルールが存在しているか」という点と「それ単体で取り扱いたいか」という点を重要視しています。
成瀬 允宣. ドメイン駆動設計入門 ボトムアップでわかる!ドメイン駆動設計の基本 (p.66). 株式会社翔泳社. Kindle 版.
その値がルールを持っているかどうかを、ドメインモデル抽出の際に書いた「仕様」から判断すると、
- User
- メールアドレス
- ハッシュ化済みパスワード
- Task
- 内容
- タスク状態
がそれぞれルールを有しています。これを値オブジェクトして扱うことにしましょう。
そうすることによって、メールアドレスというオブジェクトにバリデーションロジックを書くことができ、ロジックの散在を防ぐことができます。次、メールアドレスに関するルールが追加されても、「書くべき場所はメールアドレス値オブジェクトのところだ」と認識できるようになります。
「設計」パートはこの辺にしておきます。本格的にドメインモデリングをやろうとするとこんなに簡単な話ではありませんが、今回の設計はあくまで超簡易的なものと捉えてください。
次章から、ドメイン層の実装に入っていきます。
ドメインモデルをドメインオブジェクトにコードとして落とし込んでいきます。今回は、エンティティや値オブジェクトの性質に関してあまり言及しませんでしたが、コードを書く中で触れていきます。また、ドメインサービスという概念も登場します。
ドメイン駆動設計についてもっと詳しく知りたい方は別の方の記事や書籍を読んでくださいね!