little hands' lab

ドメイン駆動設計を布教したい

ドメイン知識とユースケースの違いは何か?[ドメイン駆動設計][DDD]

DDDの文脈の中で、
「ドメイン知識とユースケース(≒アプリケーションの知識)は何が違うのか?」
という疑問がよく持たれます。
この記事ではその違いを説明し、DDDのコードにどう反映するかを書きます。

あるToDoアプリの仕様

事例として、ToDoアプリの話をします。
「仕様を決める」と言ったとき、以下のように箇条書きで決めることがあると思います。(Jiraのようなチケット管理システムのチケット詳細として書いたりしますよね)

  • ユーザー登録、非活性化ができる
  • メールアドレスは重複登録できない
  • タスク登録、更新、完了、未完了に戻す、延期、ユーザーへのアサインができる
  • タスクは3回までしか延期ができない
  • 非活性化されていないユーザーにアサインができる
  • タスクを完了、アサインするとタスクレポートが作成される

これはいわゆる「ビジネスロジック」と呼ばれて、3層レイヤーのアーキテクチャではBusinessLogic層と呼ばれる層に書くように決めたりします。

f:id:little_hands:20190726070937p:plain:w200

さて、ここまでに何か問題はあるでしょうか?

身に覚えのある方はいらっしゃると思いますが、そう、 BusinessLogic層がどんどん肥大化していきます。

XxxService, XxxLogicと言ったメソッドが超大量にあるクラスを見たことがある方も多いのではないでしょうか。

これを避けるにはどうしたら良いでしょうか。

ユースケース図

ここで、先ほどの「仕様」と書いたものを、ユースケース図とルール/制約という観点で整理してみます。

ます、ユースケース図を書いて見ます。

f:id:little_hands:20190726070950p:plain:w300

ルール/制約

次に、このアプリケーションのルール/制約を整理してみます。

  • ユーザー
    • メールアドレスは重複登録できない
    • 最初は活性状態で作成され、非活性化できる
    • ユーザーは姓名、メールアドレスを持つ
  • タスク
    • タスクは期日を持ち、3回まで延期ができる
    • 非活性化されていないユーザーにアサインができる
    • 最初は未完了状態で作成される

元の仕様を二つに分けることができました。

ここで改めて見てみると、元の「仕様」には
性質が大きく異なるものが一緒に並べられていた
ということに気づくことができるのではないでしょうか。

後者に分類されるルール/制約のことを、「ドメイン知識」と呼びます。

この2つについて定義を書きます。

  • ユースケース
    • ユーザーとソフトウェアの間の相互関係を起こすアクション
    • "このソフトウェアの"ユースケースであり、アプリケーションがなければ存在しない
  • ドメイン知識
    • ソフトウェア化する対象領域に存在するルール
    • ソフトウェアがなくても、現実世界に存在する

ドメイン知識についての補足

「ドメイン」というのは、現実世界のソフトウェア化する対象のことを指します。ドメイン知識は、現実世界における知識、という意味合いが含まれます。

例えば、ソフトウェアを作る前に、ToDoを付箋で管理していたとします。
その際にも「付箋に期日を書くようにする」「日付は3日までしか伸ばしてはいけない」というルールで運用することは可能です。今回の開発において、実際に現実にあったルールを、ソフトウェアに落とし込むという捉え方ができるのです。

一方、例えば入力値のバリデーションとかユーザー認証という概念は、ソフトウェアがなければ存在しません。

このように、現実世界にあるルール/制約か、そうでないかという観点で、ドメイン知識とそうでないかを切り分けることができます。

アーキテクチャとの関係

新卒にも伝わるドメイン駆動設計のアーキテクチャ説明で紹介した以下のアーキテクチャを見て見ましょう。

もとはBusinessLogic層に詰め込まれていたものが、切り分けたユースケース/ドメイン知識に基づいてそれぞれApplication層(UseCase層)、Domain層にマッピングされます。
これにより、冒頭で懸念してしていた、BusinessLogic層の大幅な肥大を防ぐことができます。レイヤの責務がより明確になり、凝集度が上がり、コードのメンテナンス性を大幅に向上することにつながります。

ドメインモデリング

DDDで実装前に行うドメインモデリングでは、ユースケースとドメイン知識を順番に整理するところから始めます。
現場でDDD!のハンズオン、持ち帰ってやってみたではその具体例を紹介しました。

まとめ

このように、ユースケースとドメイン知識を切り分け、実装にも反映することで、コードの凝集度を大きく上げてメンテナンス性が高いコードを書けるようになります。
この際に、必ずしもDDDのEntityなどの実装パターンを使用する必要はありません。まずはレイヤーで分けるだけでも大きな違いが出ます。
今までは区別していなかったものについて、ぜひ意識を向けて試して見てください。

終わりに

TwitterでもDDDの話をつぶやいてるのでよろしければフォローしてください。
記事に関するご質問もお気軽にどうぞ!

松岡@DDDブログ書いてます (@little_hand_s) | Twitter