ドメイン駆動設計の練習!!サンプルプログラム実装編|ユースケース作成

はじめに

データベーススペシャリストの過去問(2021年秋午後Iの問1)を例に、

ドメイン駆動設計でモデリングをしてユースケースのサンプルプログラムとテストコードを

作成したので(Java + Springで作成)、

 

ドメインモデル図をベースにユースケースを実装していく際に感じたことや気付き、

僕のユースケースに対する役割の解釈などについて、

本記事にまとめました。

 

>>モデリング結果(drawio)

>>モデリング対象(データベーススペシャリスト2021秋午後I問1)

 

ドメイン駆動設計の練習モデリング編についてはこちらにまとめています。

ドメイン駆動設計の練習!!モデリング編

 

MEMO

本記事では、

松岡さんの「サンプルコード&FAQ」、「モデリング/実装ガイド」を参考にさせて頂きました。

サンプルプログラムの作成及びテストコードの作成は本をなぞった形になります。

(その点お含みおきください)

 

2022/03/22追記

ドメイン駆動設計でモデリング〜コーディング〜テストコード作成

までのまとめ記事を作ったので興味がある方は是非みてください。

ドメイン駆動設計の練習!!モデリング〜サンプルプログラム・テストコード作成(まとめ記事)

 

ドメイン駆動設計におけるユースケースとは??他の層との役割分担は??

ユースケースについて本ではこのように述べられていました。

ユースケースクラスは、ドメイン層のクラスが公開しているメソッドを組み合わせてユースケースを実現します。具体的には、ドメインオブジェクトの生成や状態の変更、リポジトリを使用した永続化などを行います。

ドメイン駆動設計 モデリング/実装ガイド 第7章(松岡 幸一郎)

 

 

ユースケースクラスでは、ドメイン層のオブジェクトを組み合わせて1つのユースケース

(モデリングの際に作成したユースケース図の中の「支払情報を登録する」など)

を実現するのが役割です。

 

例えばサンプルの例でいうと、

支払において「支払日には未来日が設定できない」といったチェックを

ユースケースクラスで行ったり(ドメイン層の役割)、

 

画面に表示のために1000000→¥1,000,000といったカンマ付き円表記の文字列に

変換したり(プレゼンテーション層の役割)

 

をさせるのは避けましょう!!

 

ユースケース層とプレゼンテーション層どちらでエンティティを作成すべきか

本ではこれを原則とすべきと書かれていました。

 

 

APIのリクエストとして受け取ったXxxRequestを一度ユースケースに渡す形にXxxParamに変換し、

ユースケースからドメインオブジェクトを生成する。

ユースケースからプレゼンテーション層に返却する際は一度XxxDtoに変換して返却し、

さらにプレゼンテーションでXxxResponseというAPIのレスポンスの形に変換して返却する。

 

こう見ると変換作業がかなり多いし、XxxRequestとXxxParamやXxxResponseとXxxDtoは、

そこまで違いが出そうにないけどここまでやるんだ。。。というのが初見での感想でした。

これに対する自分なりの解釈は後述します。

 

ドメインモデル図からユースケース層の実装〜テストコード作成

作成したユースケースとテストコードについてポイントに絞って紹介します。

今回実装したユースケースはユースケース図のここです。

 

 

 

支払登録ユースケースのパッケージ

>>該当ソース(github)

ユースケースパッケージの中に支払パッケージを作成してその中には、

支払登録ユースケースとユースケースに渡されるParam、ユースケースが返却するDtoとを用意しました。

 

支払登録ユースケース

>>該当ソース(github)

支払登録ユースケースは受け取ったParamから支払エンティティ、ポイント履歴エンティティを作成します。

例えばParamの値として支払明細のない支払などであればエンティティ作成時に、

エンティティ側でDomainExceptionをスローします。

(ユースケースにチェックロジックをガリガリ書いたりしなくて済みます)

 

また、集約をまたぐが必要なのでドメインサービスを利用してチェックしています。

ドメインサービスの詳細はこちらにまとめているので参照ください

ドメイン駆動設計の練習!!サンプルプログラム実装編|ドメインサービス作成

 

他にもリポジトリを利用して支払やポイント履歴を登録します。

 

というのがざっくりユースケースにさせていることです。

 

支払登録ユースケースのテストコード

>>該当ソース(github)

 

ユースケースは受け取ったParamからエンティティを作成し、

そのエンティティをリポジトリに正しく受け渡してリポジトリを使う(登録や検索)必要があります。

 

実際にリポジトリがDBに接続して正しい値を登録、取得できることのテストは別途リポジトリのテストで

行う想定です。

リポジトリ関連はこちらにまとめているので参照ください。

ドメイン駆動設計の練習!!サンプルプログラム実装編|リポジトリ作成

 

そのため、ユースケースのテストとしては主にリポジトリをMockitoでモックしてリポジトリに、

正しくエンティティを渡せているか??という観点のテストを書いています。

 

今回のサンプルテストコードのポイントとしては2点です。

1点目は、

ユースケースでは、ドメインサービスを利用して支払時にユーザの残ポイントを上回るポイント利用が

行われていないことをチェックします。

その際ユーザリポジトリでユーザ情報を取得する必要があるのですが、

あるユーザ IDが渡されると必ずあるユーザオブジェクトを返却するようにモックしてテストしています。

 

2点目は、

ユースケースでは、支払とポイント履歴リポジトリを利用してDB登録を行います。

テストではDB登録処理は実際には行わず、リポジトリに渡されたエンティティをキャプチャして、

期待値と比較しています。

 

MEMO

これらのユースケース層のテストのやり方は本を完全になぞった形ですが

(恥ずかしながらそもそも自分で手を動かしてMockito使うの初でした)、

こうやってモックしてテストすれば無駄にDBと繋いで時間をかけて必要以上のテストはしなくて済むのと、

ユースケース層で本来の役割だけ実装していれば、確かにこのテストで十分品質担保できると実感しました。

 

 

ユースケースのサンプルコードを作成してみた感想や気付き

僕が作ったサンプルが単純だったせいもあるのですが、

プレゼンテーション層とユースケース層との連携で、

APIのリクエストをXxxParamに一度変換してユースケースに渡すのと、

ユースケースからレスポンスを一度XxxDtoに変換してプレゼンテーションに渡すメリットを

あまり感じることが現状できていません。

 

プレゼンテーション層でドメインオブジェクトいきなり生成してユースケースに渡せば変換コストかからないし、

シンプルなのでは??としばらく悩みました。。。。

 

しかし、

ユースケースの役目は、受け渡された値からドメインオブジェクトを生成してそれらを組み合わせて

ユースケースを実現することです。

なので、ドメインオブジェクト生成をプレゼンテーション層に任せると役割がぼやけるんだろうなと思います。

 

また、ドメインオブジェクト生成が複雑で〇〇という条件を満たしていれば(しかも複数集約みて判断とか)

ドメインオブジェクトを生成できる。というようなファクトリーを使うような複雑な話になってきた場合、

プレゼンテーション層でいきなりドメインオブジェクトを生成しているとそのあたりもさせることになり、

明らかに役割外のことをさせることになってしまうだろうなということが想像できます。

 

大きくこれら2つを考慮すると確かにマッピングは必須なのだと思います。

 

また、凝集度を高めるという意味でも、

ユースケースクラスはドメインサービスと同じように1つのユースケースに対してexecuteメソッド1つとし、

ユースケースクラス名もユースケース図とマップさせて命名することで、ごちゃごちゃしなくて済みそうです。

(今回のサンプルプログラムでもそのような考えで作成しています)

 

コメントを残す

メールアドレスが公開されることはありません。

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください