Open3
『手を動かしてわかるクリーンアーキテクチャ』読書メモ
結論
パッケージ構成
アーキテクチャの構成要素を意識して、以下のようなパッケージ構成にする。
$ tree src/main/java/com/example/app_name
src/main/java/com/example/app_name
├── adapter
│ ├── in
│ │ └── web
│ └── out
│ └── persistence
└── application
├── domain
│ ├── model
│ └── service
└── port
├── in
└── out
Spring Bootでのクラス配置
src/main/java/com/example/app_name
├── adapter
│ ├── in
│ │ └── web # @Controllerクラスやクライアント向けDTO等(*1)
│ └── out
│ └── persistence # @Repository, @Entityクラス等
└── application
├── domain
│ ├── model # ドメイン駆動設計でのモデル。
│ └── service # @Service, @Transactionalクラス等のドメイン駆動設計での
│ # アプリケーションサービス、ドメインサービス(*2)。
└── port
├── in # adapter.inから利用される、外部システムからの呼び出し用Interface
│ # Validationを行う入力モデルクラス(*3)
└── out # adapter.outで実装される、外部システムへの保存・送信用Interface(*4)
*1: Controllerクラスは@Mapping毎にクラスを分ける事が推奨されている。(テストクラスが肥大化しやすい。ReadやUpdateの内容がごちゃまぜになりやすい。)
*2: この本では、ドメイン駆動設計でのアプリケーションサービスとドメインサービスの区別は微妙な判断を強いられるので、分けなくてもよいという立場である。
*3: この本ではCommandやQueryと名付けられている。一般的なexecute()メソッドを持つCommandパターンのCommandとは違うので要注意。コマンドクエリ責務分離の方を指している。
*4: データベースのCRUDのような操作は、C, R, U, D毎にInterfaceを分ける。(Repositoryが複数のInterfaceを実装するのは構わない。集約毎にRepositoryを作成する等)
パッケージの作成方法
まとめてJavaのパッケージを作成する方法。(gitにコミットするために.gitkeepファイルも作成)
cd src/main/java/com/example/app_name
for DIR in adapter/in/web adapter/out/persistence \
application/domain/model application/domain/service \
application/port/in application/port/out
do
mkdir -p $DIR
touch $DIR/.gitkeep
done
例: ヘキサゴナル・アーキテクチャのコーヒーポット管理システム
全体図
パッケージ構成
テスト
単体テスト
domainパッケージのクラス、ドメインモデルやユースケースについて単体テストを行う。永続化アダプタや外部送信アダプタなどは、テストダブルを使うようにする。
統合テスト
Webアダプタ
コントローラー部分のみを取り出してテストする。
@WebMvcTest(controllers = GetCoffeePodController.class)
class GetCoffeePodControllerTest{
@AutoWired
private MocMvc mockMvc;
@MockBean
private GetCoffeePodUseCase;
private static final String ENDPOINT = "/coffee-pod/{id}";
@WebMvcTest
void test指定したIDのポッドが存在する場合はポッドの情報を返す() {
mockMvc
.perform(
get(ENDPOINT, "foo-uuid"))
.andExpect(status().isOk());
then(GetCoffieePodUseCase).should(
.getCorffiePod(eq("foo-uuid")));
}
}
永続化アダプタ
TestContainer等を使って、実際のDBにアクセスしてテストすると良い。
システムテスト
外部システムも含めて、テスト用のシステムを起動してテストを行う。TestRestTemplateクラスを使ってテストするとよい。JGiven等の振る舞い駆動開発用ツールを使うのも検討する。