DDDを意識した際のpackage構成

公開:2020/09/25
更新:2020/10/08
3 min読了の目安(約2800字TECH技術記事

概要

DDDを勉強した際に増田さんlittle_handsさんnrsさんのサイトをよく拝見させて頂いているのですが、実際に自分でDDDで取り入れた際にpackage構成をどうした方がいいかというのを考えることが多いので備忘録と考えの整理の為に残します

DDDに関しての自分のメモを元に書いています

アーキテクチャ

isolating-the-domainのアーキテクチャが個人的にはしっくりきています

外部との接地面はPresentation層とInfrastructure層のみでApplication層やDomain層は自分たちの関心毎に集中しやすくなっています

package構成

root
├── application
│   ├── service(ApplicationService)
│   └── sharedservice(サービス間で使いたいサービス)
├── domain
│   ├── model(値オブジェクトなどを格納したオブジェクト)
│   ├── repository(インターフェース)
│   ├── service(DomainService)
│   └── value(値オブジェクトや区分オブジェクト)
├── infrastructure(repositoryの実態)
│   ├── datasource(DBなど)
│   ├── externalapi(外部APIなど)
│   ├── composite(複数のdatasourceやexternalapiの結果を結合したりする場合に使用)
│   └── transfer(外部ストレージなど)
└── presentation
    ├── controller
    ├── secutiry(認証関連やCSRFトークンなどの処理)
    └── interceptor(コントローラー共通処理)

Application層のServiceとDomain層のServiceの違い

ApplicationService:ユースケース(プロジェクトの作成、参照、更新、削除)
DomainService:ドメインオブジェクトに関する操作だがドメインオブジェクト内にはおけない物(プロジェクトの重複確認など)

DomainServiceを使う機会は滅多にないです

ボトムアップドメイン駆動設計での説明がわかりやすかったです

ドメインオブジェクトの定義

model

値オブジェクトなどを格納したオブジェクト(Entity)

value

値オブジェクトや区分オブジェクト(ValueObject)

collection

modelやvalueなどを束ねたオブジェクト(Listなどのwrapper
置き場所は元のオブジェクトと同階層に置くのでmodelだったりvalueだったりする
名称は元のオブジェクトの複数形にする(またはsuffixにCollectionとつけるなど

参考:DDD基礎解説:Entity、ValueObjectってなんなんだ

外部オブジェクトとの変換はDTOに任せる

DBから取得した値を直接modelやvalueに変換するとやりづらいことが多かった
変換用のDTOを用意してドメインオブジェクトへの変換を任せることで特に外部APIのレスポンスの形式などを意識しなくていい

各DTOの名称は下記のように用途毎に分ける

リクエスト関連:Form(Web)、Request(API)
レスポンス関連(JSON):Response、View
DBや外部API:Entity

APIの場合はOASによるgeneratorを活用すればリクエスト関連、レスポンス関連のオブジェクトは自動生成することができる

generatorでオブジェクトを作成した場合にはControllerと同階層にConverterを用意し、ドメインオブジェクトの生成を行うようにする

packageをどこまで切るべきか

Application層のserviceやsharedservice、Domain層のrepositoryやserviceに関してはpackage直下にファイルを作成してしまうで良さそう
上記以外の物に関しては用途毎のpackageを切った方がいい

例えばdatasourceなどの場合だと実際にアクセスを行うMapperやDTO、Mapperを呼び出すクラス(repositoryのインターフェースを継承)などを置くことになる為、packageを切らないとごちゃごちゃしてしまう
Serviceなどに関してはServiceからしか呼ばないものなどはないため、packageを切る必要性が低い

Spring BootとMybatisを利用する場合には下記のような設定を入れることでXMLファイルに関しても同package内で管理することができ便利である(サンプルはGradleを使用

sourceSets {
    main {
        // mybatis SQL map XMLファイルをjava以下にも設置できるようにする
        resources.srcDir 'src/main/java'
    }
}

雑感

package構成やドメインオブジェクトなどは運用をしていく上で手を加えていくべきものである為、まだ変更のしやすさを実感できているわけではないので今後どうなるかは気になるところです

運用等をしていった結果変わった点などはまた残していけたらと思います