Droidux: ReduxをAndroidに持ち込んで状態管理から解放されよう！

本稿は[potatotips #23][potatotips]でのトーク内容『[**"Predictable state container" and DataBinding**][slide]』をそれっぽく文字に起こしたものになります（実際のLTよりは丁寧に，よりポエムっぽく書いてます）．

何か間違い等があればコメント等で優しく教えていただけると幸いです．また，議論も大歓迎です．

## TL;DR
* JSとAndroid・iOSは全く違う環境に見えて目的は近いのでは？
* JS界の爆発的成長をAndroidに取り入れてみよう！
* 2015年フロントエンドWebのトレンドなライブラリである[Redux][redux]をAndroid向けに実装してみたよ => [**Droidux**][droidux]

## Introduction
Androiderのみなさんから見てJavaScript界隈はどんな風に見えますか？
「jQueryはオワコン！」「Angularは死んだ！」「これからはReactとFluxの時代！」のように1年ごとに目まぐるしく切り替わっていくトレンドを「たいへんそうだなあ」と遠くから眺めている みたいな方が多いと思います．

しかし，個人的には**Java（Android Java）とJavaScript（Web frontend JavaScript）を書く目的はある程度共通している**と考えています．

* ユーザインタフェースを構築する
* ユーザのインタラクションを適切に捌く
* アプリケーションの状態をいい感じに管理する

などですね．ということは，この爆速で進化していくJavaScriptの文化をAndroid（あるいはiOSのモバイルアプリ等）に取り入れることができれば，AndroidでもJS界の発展の恩恵をうけることが出来るのではないでしょうか．

本稿では先ほどの「共通の目的」から以下の2点にフォーカスし，JSにおける文化をAndroid Javaに取り入れるとどうなるか という話をしていきます．

> * ユーザのインタラクションを適切に捌く
> * アプリケーションの状態をいい感じに管理する


## Application architecture on Android/JavaScript
### Android
Androidにおけるアプリケーションアーキテクチャでは，**MVC**（Model - View - Controller）を聞くことが多いような気がします．しかし，以下の2記事のようにAndroidにおけるMVCは意外とツラいこともたくさんあったりするようです．

> * Android開発していると、なんかMVCうまくいかないなぁとモヤモヤしてきました
>   - <cite>[AndroidではMVCよりMVPの方がいいかもしれない - Konifar's WIP][konifar]</cite>
> * 実はAndroidではMVCの採用は結構つらいものがあります。
>   - <cite>[[ Android ] – これからの「設計」の話をしよう | NET BIZ DIV. TECH BLOG][kgmyshin]</cite>

MVCがツラい！ということに至ると，**MVP**（Model - View - Presenter）の方に移行する方が多いようです．また，最近は[The clean architecture][clean]のようなものの採用もあるようです（本稿ではこれらの詳細には触れません）．

### JavaScript
#### MVW
JavaScriptでもやはりMVなんちゃら（ここではMVW: Model - View - Whateverと呼びましょう）が主流である時期がありました，有名どころではAngularJSの1.x系やBackbone.jsがわかりやすくそんな感じですね．

### Flux
よりリッチな環境を求める人たちの影響もあり，Webは狂気のスピードで発展を続けていきます．Single Page Application（SPA）などの発展・需要増加に伴いMVCでは複雑すぎる！スケールしない！とか言い出す人達が出てきました．そこでFacebookが出してきた新たなライブラリ，『[なぜ仮想DOMという概念が俺達の魂を震えさせるのか - Qiita](http://qiita.com/mizchi/items/4d25bc26def1719d52e6)』などの影響もあり，日本においても流行の兆しを見せたのが[React.js](https://facebook.github.io/react/)，そして[**Flux**][flux]です（ReactはUIコンポーネント周りのライブラリなので今回は触れません）．Fluxは"[Flux eschews MVC in favor of a unidirectional data flow](https://facebook.github.io/flux/docs/overview.html)"ともある通り，MVCの複雑さを避け，単方向のデータフロー（**unidirectional data flow**）を意識するというアーキテクチャです（Fluxについて概要をサッと理解するには@azuさんの[10分で実装するFlux][azu-flux]という資料がおすすめです）．

以下は公式サイトに掲載されているデータフロー図です．

> ![flux-simple-f8-diagram-explained-1300w.png (142.0 kB)](https://img.esa.io/uploads/production/attachments/2063/2015/11/15/3140/c730efea-a42f-4ba7-931d-3acc8919ac32.png)
>
> <cite>[Flux | Application Architecture for Building User Interfaces][flux]</cite>

図を見れば明らかにデータが一方向に制限されていますね．いろいろ書いてありますが，個人的には「**Observerパターンに名前をつけてgoto化を回避したもの**」と理解するのがシンプルではないかと思っています．

### Redux
前節の図を見ての通りですが，Fluxは比較的登場人物も多く記述が冗長になりがちです．そこで次に出てきたのが[Redux][redux]です．僕がグダグダ書くよりは[Introduction to Redux // Speaker Deck][axross-redux]を見ていただくのが一番早いと思います．

> <script async class="speakerdeck-embed" data-slide="38" data-id="55466701bc0f44e2831468b22ee66736" data-ratio="1.33333333333333" src="//speakerdeck.com/assets/embed.js"></script>
> 
> <cite> [Introduction to Redux // Speaker Deck][axross-redux]</cite>

Reduxには以下のような[3つのprinciple](http://redux.js.org/docs/introduction/ThreePrinciples.html)が存在します:

> * [Single source of truth](http://redux.js.org/docs/introduction/ThreePrinciples.html#single-source-of-truth)
> * [State is read-only](http://redux.js.org/docs/introduction/ThreePrinciples.html#state-is-read-only)
> * [Mutations are written as pure functions](http://redux.js.org/docs/introduction/ThreePrinciples.html#mutations-are-written-as-pure-functions)
>
> \- <cite>[Three Principles](http://redux.js.org/docs/introduction/ThreePrinciples.html)</cite>

Reduxはそのシンプルさ・明快さと実用性から瞬く間に流行の最先端を突っ走ることになったライブラリです（完全に主観・完全に別種だけど，立ち位置的にはFluxの置き換えみたいなかんじ？）． なんか誰かJSのすごい人が「2013年はAngularJS，2014年はReact.jsなら2015年はReduxだ」みたいなこと言ってたような気がしなくもないです（あいまい）．

さて，次節からはこのReduxをAndroidでも使えるように実装してみたという話が続きます．

## [Droidux][droidux]
[**Droidux**][droidux]は前節で紹介した[Redux][redux]をAndroidで使いやすいように再設計しJavaで実装したライブラリになります．

### Motivation
FacebookがFluxで言及したように，MVWは状態管理まわりが特に複雑化しやすく，アプリの規模が大きくなればなるほど辛くなってくると思います．
一方，Reduxは基本的にはSingle state/Single storeな感じで状態を管理していくので，とりあえずルートになってるStoreにaction投げとけ！みたいな雑な扱いができるので，頭悪くてもとりあえずいい感じに使えそうです（※ メモリとか考えたら1つのStoreに全部結合すると辛くなりそうなので適当に…）．

### Usage
とりあえず管理対象の状態のクラス作ります．ここではTodoListを例にします．

```java
public class TodoList extends ArrayList<TodoList.Todo> {
    public TodoList() {
    }

    public TodoList(List<Todo> list) {
        super(list);
    }

    public static class Todo {
        // pojoっぽいの
        // immutableにしとくといいことあるよ
    }
}
```

`Reducer`を定義します．`@Reducer`アノテーションに管理対象のstateのクラスを渡してあげます．また，`@Dispatchable`アノテーションに受ける`Action`のクラスを渡してあげることでいい感じに`Action`をハンドリングしてくれます．

なお，Reducerのクラス名と各Dispatchableメソッドの引数は決められていますので．違反するとprocessorがException吐いてきます．また，reducerの各メソッドの実装はオリジナルのReduxにもあるようにimmutableな感じでオブジェクト生成して返してあげると後々幸せになります（副作用減らそう）．

```java
@Reducer(TodoList.class)
public class TodoListReducer {
    @Dispatchable(AddTodoAction.class)
    public TodoList addTodo(TodoList state, AddTodoAction action) {
        TodoList newState = new TodoList(state);
        newState.add(new TodoList.Todo(action.getText()));
        return newState;
    }

    // ...
}
```

続いて，Storeクラスのinterfaceを定義します．`BaseStore`を継承し，`@Store`アノテーションにはReducerクラスを渡してあげます（複数可）．また，interfaceにはstateのGetterメソッド，stateのObservableを返すメソッドが定義できます（旧ver.だと全メソッド自動生成だったのですが，Dagger 2等のコード生成系ライブラリとの相性からこのような形に変更されました）．

```java
@Store(TodoListReducer.class)
interface RootStore extends BaseStore {
    TodoList getTodoList();
    Observable<TodoList> observeTodoList();
}
```

Storeの定義がちゃんとできていれば，Javaのannotation processorがいい感じにStoreクラス（Droidux + `interface名`）と`builder()`メソッドを生成してくれます．

```java
TodoListStore store = DroiduxTodoListStore.builder()
        .setReducer(new TodoListReducer(), new TaskList())
        .build();
```

このへんはオリジナルとは違うところで，オリジナルはReducerのfunctionたちをいい感じに`createStore()`に喰わせてあげればStoreが生成されますが，Droiduxでは（型の恩恵を最大限に受けるためにも）Storeクラスを自動で生成します．また，この自動生成の恩恵として，本来はReducer function内に記述するAction.typeによるハンドリング処理をも自動的に実装してくれるというものがあります．

あとはビルドされたstoreインスタンスに適当なActionを`dispatch()`してあげることで状態の更新を行うことができます．なお，`Store#dispatch()`は`rx.Observable<Action>`を返すため`subscribe()`が必要になることが多いでしょう．

```java
store.dispatch(new AddTodoAction("new todo1")).subscribe();
```

基本はこんな感じです．複数Reducerを結合して1つのデカいStoreクラスを生成したいときは`@Store`に対象のReducerクラスたちを渡してあげる，undo/redo機能が欲しければReducerに`@Undoable`アノテーションを付与するなど様々な拡張が可能となっています．

また，DataBindingさせたい場合はgetterに`@Bindable`アノテーションを付与してあげて，`setReducer()`に自動生成されたfield idを渡してあげることでいい感じにやってくれるようになります．

```java
@Store(CounterReducer.class)
public interface CounterStore extends BaseStore {
    @Bindable Counter getCounter();
}

CounterStore store = DroiduxCounterStore.builder()
        .setReducer(new CounterReducer(), new Counter(0), BR.counter)
        .build();
```

```xml
<layout>
    <data>
        <variable android:name="store" android:type="CounterStore" />
    </data>
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="@{store.counter}" />

    </RelativeLayout>
</layout>
```

また，非同期Actionに関しては`droidux-thunk`という拡張を入れたうえで`ThunkMiddleware`を挿入してあげればいい感じにやってくれます．これも本家と似たような方式です．

こまかいところは[README](https://github.com/izumin5210/Droidux/blob/master/README.md)や付属するサンプルアプリ等を見ていただけるといいでしょう．

* [Counter](https://github.com/izumin5210/Droidux/tree/master/examples/counter)
* [TodoMVC](https://github.com/izumin5210/Droidux/tree/master/examples/todomvc)
* [Todos with Undo](https://github.com/izumin5210/Droidux/tree/master/examples/todos-with-undo)
* [Todos with Dagger 2](https://github.com/izumin5210/Droidux/tree/master/examples/todos-with-dagger)

### ぼくがかんがえるりだっくすのいいところ
Droiduxの章でも書きましたが，個人的にはReduxの好きなところはこういうところです．

> 一方，Reduxは基本的にはSingle state/Single storeな感じで状態を管理していくので，とりあえずルートになってるStoreにaction投げとけ！みたいな雑な扱いができるので頭悪くてもとりあえずいい感じに使えそうです

だれが状態もってるのか？ みたいなのを考えず，とりあえずrootのstoreにactionをdispatchしとけばいい！ってのはシンプルでいいですよね．MVPの状態管理部分だけReduxにしてあげるのとかも良いかもしれません．

ただ，JS世界には""ブラウザ”””という神が存在します．一方でAndroidの神といえば？`Application`や`Activity`などの`Context`になるのですかね（[techbooster.fm #10](http://techbooster.org/podcast/17284/)で@laco0416がそんなこと言ってた）．Reduxのstoreは1つの神1つ与えるぐらいがバランスがいいのかもしれません（メモリ的にも）．この辺は実際に大きいアプリを実装してみないと何ともいえませんが…．


## Discussion
[Droidux][droidux]を[potatotips][potatotips]で紹介したとき，「（undo/redo機能があるから）○○といった用途に良さそう！」みたいなリアクションをする方が何人かいらっしゃいました．本家Reduxでもある程度ウリにはしている（って[rebuild.fm #114](http://rebuild.fm/114/)で言ってた）のですが，Reduxの本質はそこではないような気がしています．ReduxをAndroidに持ち込んだものであるDroiduxでも同様です．

Reduxの[Three Principles](http://redux.js.org/docs/introduction/ThreePrinciples.html)を再度確認してみましょう．

> * [Single source of truth](http://redux.js.org/docs/introduction/ThreePrinciples.html#single-source-of-truth)
> * [State is read-only](http://redux.js.org/docs/introduction/ThreePrinciples.html#state-is-read-only)
> * [Mutations are written as pure functions](http://redux.js.org/docs/introduction/ThreePrinciples.html#mutations-are-written-as-pure-functions)
>
> \- <cite>[Three Principles](http://redux.js.org/docs/introduction/ThreePrinciples.html)</cite>

Droiduxでも多少なりとも形は変えつつですが．ある程度は踏襲しています．
では，これらの原則をAndroidに持ち込んだらどうなるでしょうか． 
また，Redux以外のJS由来のアーキテクチャ・ライブラリ・思想をAndroidに持ち込んだとき，そこには広がるのはどんな世界になるでしょうか．

---

このへんの話は[**DroidKaigi 2016**][droidkaigi]にproposalを出しています．もしrejectされても，別の何処かでお話出来るかもしれません．みんなでわいわい議論しましょう．

## Conclusion
* JSとAndroid・iOSは全く違う環境に見えて目的は近い
* JS界の爆発的成長をAndroidに取り入れてみよう
* 試しに2015年フロントエンドWebのトレンドなライブラリである[Redux][redux]をAndroid向けに実装してみたよ: [**Droidux**][droidux]
* JSの知見を取り入れて，Androidアプリの設計に新たな風を
* 続きは[DroiduKaigi 2016][droidkaigi]で！

## References
### Documents
* [AndroidではMVCよりMVPの方がいいかもしれない - Konifar's WIP][konifar]
* [[ Android ] – これからの「設計」の話をしよう | NET BIZ DIV. TECH BLOG][kgmyshin]
* [Flux | Application Architecture for Building User Interfaces][flux]
* [10分で実装するFlux][azu-flux]
* [Redux][redux]
* [Introduction to Redux // Speaker Deck][axross-redux]
* [“Predictable state container” and DataBinding // Speaker Deck][slide]

### Libraries
* [facebook/flux](https://github.com/facebook/flux)
* [rackt/redux](https://github.com/rackt/redux)
* [izumin5210/Droidux][droidux]

### Others
* [potatotips #23][potatotips]
* [DroidKaigi 2016][droidkaigi]

[droidux]: https://github.com/izumin5210/Droidux/
[slide]: https://speakerdeck.com/izumin5210/predictable-state-container-and-databinding
[potatotips]: http://connpass.com/event/21750/
[redux]: http://redux.js.org/ 
[konifar]: http://konifar.hatenablog.com/entry/2015/04/17/010606
[kgmyshin]: http://tech.recruit-mp.co.jp/mobile/android-architecture/
[clean]: https://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html
[axross-redux]: https://speakerdeck.com/axross/introduction-to-redux
[flux]: https://facebook.github.io/flux/
[azu-flux]: http://azu.github.io/slide/react-meetup/flux.html
[databinding]: http://developer.android.com/tools/data-binding/guide.html
[droidkaigi]: https://droidkaigi.github.io/2016/