ドメイン駆動設計でのサンプルプログラム実装例|ユースケース層

はじめに

ドメイン駆動設計でモデリング〜設計〜サンプルプログラム・テストコード作成

までを一通りやってみての気づきや重要ポイントをまとめました。

今回はドメインオブジェクトを組み合わせてユースケースを実現する

ユースケース層(アプリケーションサービス)にフォーカスしてまとめています。

 

本記事ではドメイン駆動設計のモデリング結果をベースに作業しています。

モデリングについてはこちらを参照ください。

ドメイン駆動設計のモデリング練習|データベーススペシャリストの過去問を題材に

 

MEMO

松岡さんの「サンプルコード&FAQ」「モデリング/実装ガイド」、

成瀬さんの「ドメイン駆動設計入門」を参考にさせて頂き、

自分の理解をまとめた記事です。(その点お含みおきください)

 

 

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

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

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

ドメイン駆動設計 モデリング/実装ガイド 第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と繋いで時間をかけて必要以上のテストはしなくて済むのと、

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

 

 

ユースケース層のサンプルコードを作成して感想や気付きなどまとめ

今回はサンプルがシンプルだったので当たり前かもしれませんが、

ユースケース層はシンプルに作れます。

シンプルに作れるようドメイン層のモデリングや設計が重要になる!!

 

さらにこれを保守することをイメージすると・・・

プレゼンテーション層がドメイン層に依存しないようにわざわざ変換処理をかましているおかげで、

プレゼンテーション層の変更がドメイン層に波及しないようになっている点で、

この変換処理はわざわざする価値があるのだなと思います。

 

また、凝集度と言う観点で、

ユースケースクラスexecuteメソッド1つとし、

インスタンス変数も全てメソッドで利用しており、

 

とあるユースケースにクラスが特化していて

ソースコードの見通しも見やすいなと言う印象です。

逆にユースケース単位にクラスができてバラバラするので、

パッケージ構成で工夫が必要になると思います。

 

おまけ

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

までを実際に行ってみてのまとめ記事を作ったので興味がある方はご覧ください。

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

 

また、

動画でもDDDを現場で実践したり既存の設計を改善した話をしているので

興味がある方は是非参考にしてみてください!!

 

 

 

コメントを残す

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

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