ことりんと一緒 Springもね - 7. サービス層

## 概要 / 説明
Kotlinでサーバーサイドアプリケーションを作ってきましたが、まだきちんとした構成にはなっていない状態です。
「[ことりんと一緒 Springもね - 2. RestController と Data Class](https://qiita.com/shinyay/items/38c5520ec5336be6de0f)」 でコントローラクラスを作り、直接データを扱うような構成のままです。
そこで、少しずつ変更を行っていきます。
まず、ここでは「**サービス**」層を考えていきます。

![service-layer.png](https://qiita-image-store.s3.amazonaws.com/0/127983/16ebac68-0d00-db04-84dd-5384b0353c40.png)

Webアプリケーションでは大きく分けて次のような機能が必要となります。

- リクエスト/レスポンスの処理
- アプリケーションロジックの処理
- データの処理

今まではこれらの機能を単一レイヤで担当していました。
このままの構成だと、扱うロジックが増え、データモデルが複雑になってくると、
１つのクラスが巨大になり開発/保守効率が悪くなってしまいます。

それぞれの機能を分離して、複数のレイヤに分けていきます。

さて、作っていたクラスが `RestController` ということで、
本来はリクエスト/レスポンスを扱うことを責務とします。
そこで、それ以外の処理を切り出し、それを **サービス** とします。

## 前提 / 環境
### ランタイムバージョン
- Kotlin : 1.3.0
- SpringBoot : 2.1.0.RELEASE

### Spring Dependencies
- Web
- Actuator

### 開発環境
- OS : Mac
- IDE : IntelliJ IDEA
- Build : Gradle

## 手順 / 解説

### 変更前のコントローラクラス

元々は以下のようにコントローラクラスの中でデータの生成など、リクエスト/レスポンスの処理以外のことを行っていました。

```kotlin
@RestController
@RequestMapping("/messages")
class SimpleController {

    @GetMapping
    fun getMessages() : List<Message> {
        return listOf(
                Message(
                        UUID.randomUUID().toString(),
                        "First Message",
                        "This is a 1st message on ${getDate()}."
                ),
                Message(UUID.randomUUID().toString(),
                        "Second Message",
                        "This is a 2nd message on ${getDate()}."
                )
        )
    }

    private fun getDate() : String {
        val simpleDateFormat = SimpleDateFormat("yyyy/MM/dd HH:mm:ss")
        return simpleDateFormat.format(Date())
    }
}
```

### サービスクラス
元々コントローラクラスに実装していた内容を以下のようにサービスクラスに移します。

```kotlin
@Service("Message Service")
class MessageService {

    fun getMessages() : List<Message> {
        return listOf(
                Message(
                        UUID.randomUUID().toString(),
                        "First Message",
                        "This is a 1st message on ${getDate()}."
                ),
                Message(UUID.randomUUID().toString(),
                        "Second Message",
                        "This is a 2nd message on ${getDate()}."
                )
        )
    }

    private fun getDate() : String {
        val simpleDateFormat = SimpleDateFormat("yyyy/MM/dd HH:mm:ss")
        return simpleDateFormat.format(Date())
    }
}
```

サービスクラスには `@Service` アノテーションを付与します。
これによりコントローラクラスの中で Dependency Injection により利用できるようになります。

```kotlin
@Autowired
private lateinit var service: MessageService
```

`lateinit` キーワードは、インスタンスを初期化せずに宣言するときに使用します。

### 変更後のコントローラクラス
サービスクラスを使用するコントローラクラスでは、リクエスト/レスポンスに関する処理だけを担当するようにします。
以下のようにサービスクラスで実装している処理を呼び出すように変更を行います。

```kotlin
@RestController
@RequestMapping("/messages")
class MessageController() {

    @Autowired
    private lateinit var service: MessageService

    @GetMapping
    fun getMessages() = service.getMessages()
}
```

## まとめ / 振り返り
責務ごとにレイヤを分けてアプリケーションを開発するのことは、今や定石ですね。
まだ、この状態ではサービスレイヤからデータ処理を直接行うようになっているので、
次はその部分を分離していきます。

### 今回のソース
- [shinyay/spring-just-rest-kotlin/tree/first-service-layer](https://github.com/shinyay/spring-just-rest-kotlin/tree/first-service-layer)