springone 2016 報告 reactive apiの設計・実装・使用
TRANSCRIPT
Copyright©2016 NTT corp. All Rights Reserved.
SpringOne Platform報告会〜Reactive APIの設計・実装・使⽤〜
2016年9⽉3⽇岩塚 卓弥NTT ソフトウェアイノベーションセンタ
2Copyright©2016 NTT corp. All Rights Reserved.
• 名前:岩塚 卓弥
• 所属:NTT ソフトウェアイノベーションセンタ• NTTの研究所のうちソフトウェアを専⾨に扱う• ⾃部署ではソフトウェア⼯学を研究• Springベースのグループ共通フレームワークの整備を担当
• SpringOneには⼆年連続での参加
⾃⼰紹介
3Copyright©2016 NTT corp. All Rights Reserved.
• Designing, Implementing, and Using Reactive APIs
• Ben Hale - Cloud Foundry Java Experience Lead• Paul Harris - Engineer of Cloud Foundry Java Client• Stephane Maldini - Project Reactor Lead
• スライドは既に公開済み• http://www.slideshare.net/SpringCentral/designing-
implementing-and-using-reactive-apis
今⽇の元ネタ
このセッションの特徴実⽤経験に基づいたReactive APIの設計,実装,使⽤法を紹介
• https://github.com/cloudfoundry/cf-java-client
Reactorを使った活きたコード例が豊富!具体的にどんなコードを書いていくのか知りたい⼈にオススメ!
4Copyright©2016 NTT corp. All Rights Reserved.
• Reactive APIの戻り値
• Functional Style の推奨
• 条件分岐
• テスト⾟い問題
アウトライン
5Copyright©2016 NTT corp. All Rights Reserved.
• Reactive APIの戻り値
• Functional Style の推奨
• 条件分岐
• テスト⾟い問題
アウトライン
6Copyright©2016 NTT corp. All Rights Reserved.
• Mono または Flux • Mono<T> : ⾼々1つのTを返す• Flux<T> : 0以上の任意の個数のTを返す
Ractive APIの戻り値
TはCollectionでも構わないe.g. Mono<List<String>>
7Copyright©2016 NTT corp. All Rights Reserved.
• subscribeするまではただの「設計書」にすぎない• 作った設計書を戻り値として返してやる必要がある
• Mono<Void>やFlux<Void>を返すのはOK
戻り値を void にしてはいけない
8Copyright©2016 NTT corp. All Rights Reserved.
• Reactive APIの戻り値
• Functional Style の推奨
• 条件分岐
• テスト⾟い問題
アウトライン
9Copyright©2016 NTT corp. All Rights Reserved.
• 副作⽤がない,単純で⼩さなメソッドをつくる✔ 動作を検証しやすい✔ バグを作り込みにくい✔ 再利⽤しやすい
• ⼩さなメソッドを組み合わせて⼤きな処理を⾏う• 組み合わせの道具:⾼階関数
• map• filter• flatMap• concatMap• …
Functional Styleの推奨
関数を引数や戻り値とする関数
10Copyright©2016 NTT corp. All Rights Reserved.
おさらい – map / flatMap
Mono<T> / Flux<T> における各要素にT から V への関数を適⽤し
Mono<V> / Flux<V> を返す
Mono<T> / Flux<T> における各要素にT から Publisher<R> への関数を適⽤し
Flux<R>を返す
12Copyright©2016 NTT corp. All Rights Reserved.
• mapやflatMapを持つクラスは他にもある• StreamやOptionalなど• これは偶然ではなく,抽象化すると同じ形になっていることに気づく
• map : F<T>に,T→Vの関数を適⽤して,F<V>を返す• flatMap : M<T>に,T→M<R>の関数を適⽤して,M<R>を返す
余談:Mono / Flux はMonad?
Functor Monad条件:・以下の関数を持つ
・fmap : (T → V) → F<T> → F<V>・Mono / Flux それぞれのmapが
fmapに該当する
・Functor則を満たす(略)
条件:・以下の関数を持つ
・bind : M<T> → (T → M<R>) → M<R>・unit : T → M<T>
・Mono の then, Flux の flatMap /concatMap がbindに該当する
・Mono / Flux それぞれの just がunitに該当する
・Monad則を満たす(略)
13Copyright©2016 NTT corp. All Rights Reserved.
メソッド参照による組み⽴て
⾼階関数にメソッド参照を渡して繋いでいく複数引数をとるメソッドには Tuple と補助関数を利⽤
14Copyright©2016 NTT corp. All Rights Reserved.
• 順序付けられた値の組• e.g. (“Text”, 12), (“abc”, “def”, 0.3) etc.• メンバ名のない構造体のようなイメージ• 新たに型をつくるまでもないが,値を組にしたいときに有⽤
• 複数の値を返す関数の作成など
• Reactorには2〜8個組を作るためのTuple型が⽤意されている
• Tuple2<T1, T2>, Tuple3<T1, T2, T3>, …• ちなみに Scala には Tuple22 まであったりする
• 前スライドの補助関数を再確認• 2引数の関数から,2つ組のタプルを引数に取る関数に変換
Tuple
15Copyright©2016 NTT corp. All Rights Reserved.
• 仮引数を使わずに関数を定義していくコーディングスタイル
• Haskell由来の⽤語• https://wiki.haskell.org/Pointfree
• 定義が簡潔になり,可読性が上がる (やりすぎると逆効果…)• f x = x + 1
• f = (+ 1)
• Reactive APIを使⽤する際におすすめらしい• データではなく関数中⼼に考える上での助けになるとのこと• おそらく本来の意味とは異なった意味で使われていたが…
Pointfree Style の推奨
Point
Pointfree
17Copyright©2016 NTT corp. All Rights Reserved.
• Reactive APIの戻り値
• Functional Style の推奨
• 条件分岐
• テスト⾟い問題
アウトライン
18Copyright©2016 NTT corp. All Rights Reserved.
• Mono / Flux に値ではなくエラーが流れる場合もある
• エラーを扱う⽅法が⾊々⽤意されている• doOnError• mapError• otherwise• …
エラーによる条件分岐
20Copyright©2016 NTT corp. All Rights Reserved.
• Mono / Flux に何も値が流れずにCompleteする場合もある
• Emptyの場合を扱う⽅法が⽤意されている• defaultWithEmpty• otherwiseIfEmpty / switchIfEmpty• repeatWhenEmpty
Emptyによる条件分岐
21Copyright©2016 NTT corp. All Rights Reserved.
Emptyによる条件分岐の例
getPrivateDomanId, getSharedDomainIdの両⽅が Empty の場合にエラーを投げる
22Copyright©2016 NTT corp. All Rights Reserved.
• エラーでも Empty でもなく単に値で分岐したい場合もある
• if⽂を使って命令的に書けば良い• Mono / Flux のメソッドで頑張っても良いが,直感的に理解し
難くなる可能性が⾼い
値による条件分岐
25Copyright©2016 NTT corp. All Rights Reserved.
• Reactive APIの戻り値
• Functional Style の推奨
• 条件分岐
• テスト⾟い問題
アウトライン
26Copyright©2016 NTT corp. All Rights Reserved.
テスト⾟い問題
• もちろんテストはRedに…?• ならない!• ⾮同期の罠 メインスレッド ⾮同期スレッド
この仕事頼む!任せろ!
任務完了…ちょ待てよ
27Copyright©2016 NTT corp. All Rights Reserved.
CountDownLatch
• 他のスレッドの終了を待つための仕組み• Reactor特有のクラスではない
• java.util.concurrent.CountDownLatch
メインスレッド ⾮同期スレッドCountDownLatchを1にセット
任せろ!この仕事頼む!
CountDownLatchが0になるまで待つよ
CountDownLatchをカウントダウンするよ
終わった!
完了!
28Copyright©2016 NTT corp. All Rights Reserved.
同期による問題解決
CountDownLatchを使って,⾮同期スレッドの処理が済むのを待つ
すべてのテストにブロックの処理書くのは⾟すぎる…
30Copyright©2016 NTT corp. All Rights Reserved.
• 設計変更のために3.0.0.RELEASEから除かれた模様• Re-evaluate TestSubscriber API
• https://github.com/reactor/reactor-core/issues/135
• Cloud Foundry Java Clientでは独⾃に実装したものを使⽤
Reactor では依然準備中…
31Copyright©2016 NTT corp. All Rights Reserved.
• Reactive APIの戻り値• 必ず Mono か Fluxを返そう
• Functional Style の推奨• ⼤きな処理は⼩さな関数を組み合わせて作る
• 条件分岐• エラーやEmptyを特別扱いするためのメソッドがある• if⽂を使っても問題ない
• テスト⾟い問題• TestSubscriber待機…?
まとめ
32Copyright©2016 NTT corp. All Rights Reserved.
• Designing, Implementing, and Using Reactive APIs
• http://www.slideshare.net/SpringCentral/designing-implementing-and-using-reactive-apis
• Project Reactor リファレンス• https://projectreactor.io/core/docs/api/
• Cloud Foundry Java Client• https://github.com/cloudfoundry/cf-java-client/
参考⽂献