Kotlin Springboot -- Part 15 Rest と Usecase で Domain を使えるようにする ( モジュール分割後 )
Tags: kotlin, spring, ca
Published: 2022-11-16 13:41:33



## why  

前回の記事で各層のモジュールを分離して
とりあえず Rest だけは動くようにした。

今回は Rest から Domain と Usecase のモジュールも使えるようにする。

---

# Rest

---

## Rest モジュールから Domain モジュールに何も依存を足さずにアクセスする

```kotlin
package com.kaede
```

パッケージ自体はこのように、Rest, Usecase, Domain, Port, Gateway, Driver, とすべて同じものを使っている。

一方、マルチモジュールにするためにモジュールを分割した。
なのでモジュール外部のクラスの関数を使うことはこのままではできない。

特に外部モジュールだということを意識せずに
同一モジュールにあった時と同様に Domain, Usecase を使ってみる。


```kotlin
  @GetMapping("/persons")
  @ResponseBody
  fun getPersons(): String {
    val persons = personsUsecase.getAllPersons()
    val gson = Gson()
    val personsJson = persons.toJson()

    return gson.toJson(personsJson)
  }
```

toJson は Domain の拡張。

```php
Caused by: java.lang.NoClassDefFoundError: com/kaede/PersonsUsecase
```

すると Usecase がみつからないとエラーがでて
アプリケーションが落ちる。

usecase だけを追加しても

```php
e: /home/kaede/source/springboot/rest/src/main/kotlin/
com/kaede/PersonResource.kt: (18, 34): 
Cannot access class 'com.kaede.Persons'. 
Check your module classpath 
for missing or conflicting dependencies
```

Persons ドメインが見つからないとエラーでビルドできなくなる。

---

## Rest の設定ファイルに Usecase と Domain の依存を追加

rest/bulid.gradle.kts に

```kotlin
dependencies {
    implementation(project(":usecase"))
    implementation(project(":domain"))
}
```

usecase と domain のパッケージを読み込めるように設定する


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ti5ocz6g7lrni5ucbfk1.png)

その後に Gradle の象さんのポップアップしたリロードボタンを押す

基本的にはモジュール(プロジェクト)外のクラスは使えないが
こうすることでモジュール外のプロジェクトも読めるようになる。

```php
2022-11-26 21:35:27.840  INFO 1943002 --- [           
main] com.kaede.PersonApiApplicationKt         
: Started PersonApiApplicationKt in 1.915 seconds 
(JVM running for 2.309)
```

無事に起動できた。

---

# Usecase

同様に Usecase からも他のモジュールたちが読み込めるようにする。

```kotlin
@Component
class PersonsUsecase(
  private val personPort: PersonPort,
) {
  fun getAllPersons():Persons {
    return personPort.getAllPersons()
  }
```

Usecase の実装と

```kotlin
interface PersonPort {
    fun getAllPersons() :Persons
}
```

Port の実装がこちら(実装というかインターフェイスだが)

---

## 依存の記述なしで起動する

```php
Caused by: java.lang.NoClassDefFoundError: com/kaede/PersonPort
```

Port の依存を書かずに動かすと、当然 Port のクラスが
見つからないエラーが出る。

なので、Usecase の設定ファイル
build.gradle.kts に Port の依存を追加する
Domain の依存は自明。

```kotlin
dependencies {
    implementation(project(":domain"))
    implementation(project(":port"))
// ...
}
```

しかし、Port だけ追加しても

```php

***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 0 of constructor in com.kaede.PersonsUsecase 
required a bean of type 'com.kaede.PersonPort' 
that could not be found.
```

PersonPort はみつからないとでてしまう

```kotlin
dependencies {
    implementation(project(":domain"))
    implementation(project(":port"))
    implementation(project(":gateway"))
// ...
}
```

Port の先の Gateway まで Usecase の依存に追加する。

```kotlin
2022-11-26 21:46:12.453  INFO 1945207 --- [           
main] com.kaede.PersonApiApplicationKt         
: Started PersonApiApplicationKt in 1.999 seconds 
(JVM running for 2.418)
```

すると無事に起動するようになる。

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/povgq8a1d6l0k7sj2dqs.png)

以前作成した図を参照する。

Gateway が必要なのは、Port は単なる穴であるからだ。
穴単体を覗くという行為は成立しない。
穴の先が有るから、穴を覗けるのだ。

だから Port という穴と、同時に穴の先に存在する Gateway を、
Usecase からは依存として必要になる。

---

# まとめ

クリーンアーキテクチャで各層ごとにモジュールを分離した。

その後、正常に動作させるためには
各モジュールの依存先として

* Rest モジュールの build.gradle.kts 
  * Domain
  * Usecase
* Usecase モジュールの build.gradle.kts
  * Domain
  * Port
  * Gateway

まず、これらの記述が必要になる。

以上。