はじめに
ドメイン駆動設計でモデリング〜設計〜サンプルプログラム・テストコード作成
までを一通りやってみての気づきや重要ポイントをまとめました。
今回はドメインサービスにフォーカスしてまとめています。
本記事ではドメイン駆動設計のモデリング結果をベースに作業しています。
モデリングについてはこちらを参照ください。
ドメイン駆動設計のモデリング練習|データベーススペシャリストの過去問を題材に
松岡さんの「サンプルコード&FAQ」「モデリング/実装ガイド」、
成瀬さんの「ドメイン駆動設計入門」を参考にさせて頂き、
自分の理解をまとめた記事です。(その点お含みおきください)
ドメインサービスとは
1つのエンティティに持たせるには無理がある
(エンティティを跨いだりエンティティの集合を扱うようなケース)、
ドメイン知識をドメインサービスを作ってそこに持たせます。
ユーザがメールアドレスを更新する際の
既に登録済みメールアドレスでないことのチェック
を例にドメインサービスについて説明されていました。
ユーザエンティティは自分のメールアドレスを持つが、
既に登録済みチェックは全ユーザのメールアドレスに対してチェックをする必要があり、
1オブジェクトがその役割を果たすには無理があるからです。
ちなみに、
僕が作成したサンプルでは、
支払というエンティティとユーザというエンティティが存在し、
支払時の利用ポイントがユーザの所有するポイント残高を超えていないか
チェックをする際に、エンティティを跨ぐチェックなのでドメインサービスを利用しました。
エンティティを跨ぐチェックのため、
1オブジェクトがこの役目を果たすには無理があると
判断しました。
(ただ、支払い集約に支払いユーザを持たせて、
支払いユーザにこのロジックを持たせるという方が、
後で落ち着いて考えるといい気もしますが。。。ひとまずそれは置いておきます。)
ドメインサービスのサンプルコードとテストコード
作成したドメインサービスとテストコードについて、
ポイントに絞って紹介します。
利用ポイント超過チェックドメインサービス
ドメイン層パッケージの中に作成しました。
支払エンティティとユーザエンティティを受け取って、
利用ポイントが残ポイントを超えていたら
DomainExceptionをスローするだけです。
Serviceが登場すると、
なんでもできちゃう神クラスに昇格してしまうことがあるので、
クラス名はドメインサービスの役割の名前をつけ、
メソッドも1つのexecuteしか持たないようにしています。
成瀬さんの本にも書いてありましたが、
ドメインサービスは極力避けるような方針にしなければ、
エンティティに書くロジックはドメインサービスに書くこともできるので、
エンティティの知識が全部ドメインサービスに漏れてしまいがちです。
なんでもやれる複雑で厄介な神サービスは現場でよく見かけます。。。
利用ポイント超過チェックドメインサービスのテストコード
テストコードでは正常系で例外が発生しないパターンと、
例外が発生するパターンと2通りのケースを作成しました。
本で紹介されていたテスト用インスタンス生成オブジェクトを作れば、
テストコードがシュッとするのですが、
本のサンプルのようなKotlinのデフォルト引数がJavaでは使えず。。。
ドメイン駆動設計でドメインサービスのサンプルコードを作成してみた感想や気付き
極力使わないようにして、
どうしても必要な時だけサービスの利用目的を明記する形で作成。
とすることで、
なんでもやってしまう神サービスを作ってしまわないように
意識することに注意だと思います。
サービスになんでも書いちゃう方式に僕は今までの現場で慣れてしまっていたので、
気を抜くとどうしてもそっちに行っちゃいます。。。
その辺りに注意して設計されたシステムの保守を
社会人一発目の現場でできてたら、
悪い癖はつかなかっただろうなとも思います。
(だから新卒にいきなりDDDを教えるとかって話が出たりするのかな)
そういえば、、
現場ではよくUtilクラス的なのを作って
いろんなことを全部そこでやってたりもしてたなぁ。。。
おまけ
ドメイン駆動設計でモデリング〜コーディング〜テストコード作成
までを実際に行ってみてのまとめ記事を作ったので興味がある方はご覧ください。