KotlinのドキュメントのAsynchronous programming stylesを読む

# きっかけ
FluxとCoroutineを使ってイケているAndroidアプリが作りたかったので、DroidKaigiアプリで実験していました。
https://github.com/DroidKaigi/conference-app-2018/commit/cfe7a11c4e8baf6818f6398d8ac81a334eff4826
でも割と雰囲気で書いていて、よく分からなかったんですよね。。
そんな時にk-kagurazakaさんがPRを出してくれて、その時に[このドキュメント](https://github.com/Kotlin/kotlin-coroutines/blob/master/kotlin-coroutines-informal.md#asynchronous-programming-styles)が便利だと教えてくれました。
https://github.com/DroidKaigi/conference-app-2018/pull/669
なのでそこを読んでみようかなと思います。

原文はこちらです。
https://github.com/Kotlin/kotlin-coroutines/blob/master/kotlin-coroutines-informal.md#asynchronous-programming-styles

# 非同期プログラミングのスタイル
非同期プログラミングは異なるいくつかのスタイルが存在します。
コールバックは一般にcoroutineが置き換えるように設計されている最も簡単なスタイルです。(コールバックは[asynchronous computations](https://github.com/Kotlin/kotlin-coroutines/blob/master/kotlin-coroutines-informal.md#asynchronous-computations)のセクションで言及しています。)コールバックスタイルなAPIは[ここ](https://github.com/Kotlin/kotlin-coroutines/blob/master/kotlin-coroutines-informal.md#wrapping-callbacks)で示す相当する`suspending function`でラップする事ができます。

おさらいさせてください。例えばブロックする`sendEmail`関数を以下のようなシグネチャで作ったとします。

```kotlin
fun sendEmail(emailArgs: EmailArgs): EmailResult
```

この関数は操作中にスレッドの実行を長時間ブロックする可能性があります。

それをブロックしないようにするには、例えば、ブロックしないcallback-styleを代表してerror-firstな[node.js callback convention](https://www.tutorialspoint.com/nodejs/nodejs_callbacks_concept.htm)を以下のシグネチャで使うことができます。

```kotlin
fun sendEmail(emailArgs: EmailArgs, callback: (Throwable?, EmailResult?) -> Unit)
```

しかし、coroutineで他の非同期のスタイルを使うことができます。それらの一つのスタイルはasync/awaitスタイルで、それはたくさんの有名な言語に組み込まれています。Kotlinでは、このスタイルは[futures](https://github.com/Kotlin/kotlin-coroutines/blob/master/kotlin-coroutines-informal.md#futures)の使い方のセクションのパートとして示されている`future{}`と`.await()`ライブラリ関数の導入によって利用されています。
このスタイルはコールバックをパラメーターとして返すのではなく、future objectのような何かを返す事によって示されています。`sendEmail`のこのasync-style関数シグネチャはこのようになります。

```kotlin
fun sendEmailAsync(emailArgs: EmailArgs): Future<EmailResult>
```
このスタイルで`Async`を追加するのは、パラメーターが同期的に行う場合と全く同じで、その処理が非同期であることを忘れるミスをしやすいためです。`sendEmailAsync`関数は非同期処理を開始し、並行処理の落とし穴をもたらす可能性があります。しかしこのスタイルを促進しているプログラミング言語では通常、実行を必要に応じてシーケンスに戻すためのawait(待つ)基本メソッドのようなものがあります。

Kotlinの*native*プログラミングスタイルでは**一時停止(suspending)関数**ベースです。このスタイルでは`sendEmail`のシグネチャは自然に見え、パラメータや返り値などでわかりにくいものがありません。しかし`suspend`修飾子を追加しています。

```kotlin
suspend fun sendEmail(emailArgs: EmailArgs): EmailResult
```

その非同期と一時停止スタイルはこれまでに私達がみた他のスタイルに簡単に置き換えることができます。
例えば、`sendEmailAsync`は[future coroutine builder](https://github.com/Kotlin/kotlin-coroutines/blob/master/kotlin-coroutines-informal.md#building-futures)を使って一時停止する`sendEmail`で実装する事ができます。

```kotlin
fun sendEmailAsync(emailArgs: EmailArgs): Future<EmailResult> = future {
    sendEmail(emailArgs)
}
```

一時停止関数sendEmailは[await suspending function](https://github.com/Kotlin/kotlin-coroutines/blob/master/kotlin-coroutines-informal.md#suspending-functions)を利用してsendEmailAsyncで実装できます

```kotlin
suspend fun sendEmail(emailArgs: EmailArgs): EmailResult = 
    sendEmailAsync(emailArgs).await()
```

そのため、ある意味この２つのスタイルは等価で、便利さでコールバックより優れています。
しかし`sendEmailAsync`と一時停止`sendEmail`の違いを深く見てみましょう。

それらを**入れ込む**(compose)方法で始めに比べてみましょう。一時停止関数は普通の関数のように入れ込むことができます。

```kotlin
suspend fun largerBusinessProcess() {
    // ここにたくさんのコード..
    sendEmail(emailArgs)
    // その後にも続く..
}
```

対応するasync-style関数は以下のように入れ込みます。

```kotlin
fun largerBusinessProcessAsync() = future {
    // ここにたくさんのコード..
   sendEmailAsync(emailArgs).await()
    // その後にも続く..
}
```

async-style関数の入れ込む時は冗長でエラーが起こりやすいです。async-styleの例で`.await()`の呼び出しをなくしてもコードはコンパイルできて動作します。しかし、emailの送信が非同期になってしまうか、ビジネスプロセスの別の部分と同時に送信して、共有の状態を変更して、エラーを再現するのが非常に困難になる可能性があります。対照的に一時停止関数は逐次処理がデフォルトです。一時停止関数とともに、いつでもあなたが平行性が必要な時に`future{}`や似たcoroutineビルダーへの呼び出しのあるソースコード内で表現することができます。

どのようにこれらのスタイルがたくさんのライブラリを使った大きいプロジェクトで**スケール**するのか比べてみましょう。一時停止関数はKotlinで軽量なコンセプトです。全ての一時停止関数はどんなKotlin coroutineの中でも使うことができます。async-style関数はフレームワークに依存します。それぞれのpromises/futuresフレームワークはそれ自身の`async`のようなものを定義する必要があります。あらゆるpromises/futureのフレームワークは、フレームワークのpromises/futureのようなクラスとフレームワークのawaitのような関数を返す独自の非同期的な関数を定義しなければなりません。

**パフォーマンス**を比べてみましょう。一時停止関数は呼び出しごとに最小限のオーバーヘッドで提供されます。[implementation details](https://github.com/Kotlin/kotlin-coroutines/blob/master/kotlin-coroutines-informal.md#implementation-details)セクションをチェックすることができます。async-style関数では停止する仕組みに追加してとても重いpromise/futureの抽象化を維持する必要があります。いくつかのfutureのようなオブジェクトのインスタンスはasync-style関数から常に返さなければならず。それはもし関数が短く単純であるならば最適化することができません。async-styleは細かい分解には適していません。

JVM/JSのコードとの**互換性**について比べてみましょう。async-style関数はfutureのような抽象化を利用するJVM/JSコードとより互換性があります。JavaやJSではそれらはfutureのようなオブジェクトを返すただの関数です。一時停止関数は[continuation-passing-style](https://github.com/Kotlin/kotlin-coroutines/blob/master/kotlin-coroutines-informal.md#continuation-passing-style)に対応していないどの言語からでも変に見えます。しかしあなたは与えられたpromise/futureフレームワークのために簡単に一時停止関数をasync-style関数に変換する後にある例でみることができます。だからKotlinで一時停止関数を1度書くだけで、適切な`future{}`coroutine builder関数を使った一行のコードを利用して、どのpromise/futureのスタイルとも相互運用することができます。

# 感想
async-styleを使わずに書ける方が間違えにくいので良い、ということでそういう風に出来るように、プルリクエストを送ってくれたみたいで、勉強になりました。
https://github.com/DroidKaigi/conference-app-2018/pull/669/files