freeletics/RxReduxのReducerとSideEffeftの呼び出し順序を調べた

# feeletics/RxReduxとは
https://github.com/freeletics/RxRedux

RxJavaを利用して、Reduxの流れをRxのストリームに乗せて実行するフレームワーク。
AndroidでReduxアーキテクチャを採用するときに使えるはず！と調査に乗り出した。

Android + Reduxについては[こちら](https://qiita.com/Urotea/items/8cbc8f55406b6ff32bbd)を参照

# 想定読者
- RxJavaはまあまあわかる
- Kotlinがちょっと読める
- feeletics/RxReduxを使ってみようと思ったが、ReducerとSideEffectの呼び出し順序がわからない人(タイトル通り)

# 検証内容
githubに書いてある[内容](https://github.com/freeletics/RxRedux#who-processes-an-action-first-reducer-or-sideeffect)と見た目が違う挙動をしているように見えたので調査してみた。
結論としては「readmeは正しいが、ちょっと誤解しやすい気がする」

## 検証コード

```kotlin
action.reduxStore(
    initState(), // 今回は関係ないので無視してください
    listOf(this.sideEffect1, this.sideEffect2), // SideEffectを設定
    this.reducer,  // reducerを設定します。
).subscribe{}
```

この`sideEffect`の挙動によって、どのようにstreamの流れが変わるのか調査します。

### sideEffect1もsideEffect2も後ろにactionを流さない場合

```kotlin
private val sideEffect1: SideEffect<State, Action> = { a, _ ->
    a.doOnNext { Timber.d("test1 log") }.flatMap { Observable.empty<Action>() }
}
// sideEffect2も同様
```

結果
**reducer -> sideEffect1 -> sideEffect2**
考察

```
reducer -> sideEffect1
        -> sideEffect2
```

### sideEffect2が後ろにactionを流す場合

```kotlin
private val sideEffect1: SideEffect<State, Action> = { a, _ ->
    a.doOnNext { Timber.d("test1 log") }.flatMap { Observable.empty<Action>() }
}
private val sideEffect2: SideEffect<State, Action> = { a, _ ->
    a.doOnNext { Timber.d("test1 log") }
}
```

結果
**reducer -> sideEffect1 -> sideEffect2 -> reducer -> sideEffect1 -> sideEffect2 -> reducer -> 以下ループ**
考察

```
reducer -> sideEffect1
        -> sideEffect2 -> reducer -> sideEffect1
                                  -> sideEffect2 -> reducer -> 以下ループ
```

### sideEffect1が後ろにactionを流す場合

```kotlin
private val sideEffect1: SideEffect<State, Action> = { a, _ ->
    a.doOnNext { Timber.d("test1 log") }
}
private val sideEffect2: SideEffect<State, Action> = { a, _ ->
    a.doOnNext { Timber.d("test1 log") }.flatMap { Observable.empty<Action>() }
}
```

結果
**reducer -> sideEffect1 -> reducer -> sideEffect1 -> 以下ループ**
考察

```
reducer -> sideEffect1 -> reducer -> sideEffect1 -> 以下ループ
        -> (sideEffect2)          
                                  -> (sideEffect2)
* sideEffect2も呼ばれているが、sideEffect1のループがスタックしており処理が実行されていない
```

### sideEffect1が一度だけactionを流す場合

```kotlin
// 1回目にはFirstAction()が流れてくる
private val sideEffect1: SideEffect<State, Action> = { a, _ ->
    a.doOnNext { Timber.d("test1 log") }.filter { it is FirstAction() }.map { SecondAction() }
}
private val sideEffect2: SideEffect<State, Action> = { a, _ ->
    a.doOnNext { Timber.d("test1 log") }.flatMap { Observable.empty<Action>() }
}
```

結果
**reducer -> sideEffect1 -> reducer -> sideEffect1 -> sideEffect2 -> sideEffect2**
考察

```
reducer -> sideEffect1 -> reducer -> sideEffect1
        -> sideEffect2
                                  -> sideEffect2
```

## 結論

```
action -> reducer -> sideEffect1 -> reducer -> sideEffect1
                  -> sideEffect2            -> sideEffect2
                        ・                          ・
                        ・                          ・
                     sideEffectn ->         -> sideEffectn
```
といった具合に、`reducer`の後に各種`sideEffect`が呼ばれ、
`sideEffect`が後ろに`action`を流すと、また`reducer`が呼ばれその後に各種`sideEffect`が呼ばれる。
よって、各種`sideEffect`は自分が見たい`action`のみ見るように以下のように実装することが望ましい。

```kotlin
private val sideEffect1: SideEffect<State, Action> = { a, _ ->
    a.ofType(FirstAction::class.java).doOnNext { Timber.d("test1 log") }
}
```