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>を返す
11Copyright©2016 NTT corp. All Rights Reserved.
Functional Styleの例
再利⽤性の⾼いメソッド
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
16Copyright©2016 NTT corp. All Rights Reserved.
Point Free Style とされていた例
17Copyright©2016 NTT corp. All Rights Reserved.
• Reactive APIの戻り値
• Functional Style の推奨
• 条件分岐
• テスト⾟い問題
アウトライン
18Copyright©2016 NTT corp. All Rights Reserved.
• Mono / Flux に値ではなくエラーが流れる場合もある
• エラーを扱う⽅法が⾊々⽤意されている
• doOnError
• mapError
• otherwise
• …
エラーによる条件分岐
19Copyright©2016 NTT corp. All Rights Reserved.
エラーによる条件分岐の例
発⽣したエラーを捨てて別のレスポンスを返却
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 のメソッドで頑張っても良いが,直感的に理解し
難くなる可能性が⾼い
値による条件分岐
23Copyright©2016 NTT corp. All Rights Reserved.
値による条件分岐の例 - Imperative
24Copyright©2016 NTT corp. All Rights Reserved.
値による条件分岐の例
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を使って,⾮同期スレッドの処理が済むのを待つ
すべてのテストにブロックの処理書くのは⾟すぎる…
29Copyright©2016 NTT corp. All Rights Reserved.
TestSubscriber
同期させるためのコードを⾃分で書く必要がない
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/
参考⽂献

SpringOne 2016 報告 Reactive APIの設計・実装・使用

  • 1.
    Copyright©2016 NTT corp.All Rights Reserved. SpringOne Platform報告会 〜Reactive APIの設計・実装・使⽤〜 2016年9⽉3⽇ 岩塚 卓弥 NTT ソフトウェアイノベーションセンタ
  • 2.
    2Copyright©2016 NTT corp.All Rights Reserved. • 名前:岩塚 卓弥 • 所属:NTT ソフトウェアイノベーションセンタ • NTTの研究所のうちソフトウェアを専⾨に扱う • ⾃部署ではソフトウェア⼯学を研究 • Springベースのグループ共通フレームワークの整備を担当 • SpringOneには⼆年連続での参加 ⾃⼰紹介
  • 3.
    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を使った活きたコード例が豊富! 具体的にどんなコードを書いていくのか知りたい⼈にオススメ!
  • 4.
    4Copyright©2016 NTT corp.All Rights Reserved. • Reactive APIの戻り値 • Functional Style の推奨 • 条件分岐 • テスト⾟い問題 アウトライン
  • 5.
    5Copyright©2016 NTT corp.All Rights Reserved. • Reactive APIの戻り値 • Functional Style の推奨 • 条件分岐 • テスト⾟い問題 アウトライン
  • 6.
    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>>
  • 7.
    7Copyright©2016 NTT corp.All Rights Reserved. • subscribeするまではただの「設計書」にすぎない • 作った設計書を戻り値として返してやる必要がある • Mono<Void>やFlux<Void>を返すのはOK 戻り値を void にしてはいけない
  • 8.
    8Copyright©2016 NTT corp.All Rights Reserved. • Reactive APIの戻り値 • Functional Style の推奨 • 条件分岐 • テスト⾟い問題 アウトライン
  • 9.
    9Copyright©2016 NTT corp.All Rights Reserved. • 副作⽤がない,単純で⼩さなメソッドをつくる ✔ 動作を検証しやすい ✔ バグを作り込みにくい ✔ 再利⽤しやすい • ⼩さなメソッドを組み合わせて⼤きな処理を⾏う • 組み合わせの道具:⾼階関数 • map • filter • flatMap • concatMap • … Functional Styleの推奨 関数を引数や戻り値とする関数
  • 10.
    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>を返す
  • 11.
    11Copyright©2016 NTT corp.All Rights Reserved. Functional Styleの例 再利⽤性の⾼いメソッド
  • 12.
    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則を満たす(略)
  • 13.
    13Copyright©2016 NTT corp.All Rights Reserved. メソッド参照による組み⽴て ⾼階関数にメソッド参照を渡して繋いでいく 複数引数をとるメソッドには Tuple と補助関数を利⽤
  • 14.
    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
  • 15.
    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
  • 16.
    16Copyright©2016 NTT corp.All Rights Reserved. Point Free Style とされていた例
  • 17.
    17Copyright©2016 NTT corp.All Rights Reserved. • Reactive APIの戻り値 • Functional Style の推奨 • 条件分岐 • テスト⾟い問題 アウトライン
  • 18.
    18Copyright©2016 NTT corp.All Rights Reserved. • Mono / Flux に値ではなくエラーが流れる場合もある • エラーを扱う⽅法が⾊々⽤意されている • doOnError • mapError • otherwise • … エラーによる条件分岐
  • 19.
    19Copyright©2016 NTT corp.All Rights Reserved. エラーによる条件分岐の例 発⽣したエラーを捨てて別のレスポンスを返却
  • 20.
    20Copyright©2016 NTT corp.All Rights Reserved. • Mono / Flux に何も値が流れずにCompleteする場合 もある • Emptyの場合を扱う⽅法が⽤意されている • defaultWithEmpty • otherwiseIfEmpty / switchIfEmpty • repeatWhenEmpty Emptyによる条件分岐
  • 21.
    21Copyright©2016 NTT corp.All Rights Reserved. Emptyによる条件分岐の例 getPrivateDomanId, getSharedDomainIdの 両⽅が Empty の場合にエラーを投げる
  • 22.
    22Copyright©2016 NTT corp.All Rights Reserved. • エラーでも Empty でもなく単に値で分岐したい場合も ある • if⽂を使って命令的に書けば良い • Mono / Flux のメソッドで頑張っても良いが,直感的に理解し 難くなる可能性が⾼い 値による条件分岐
  • 23.
    23Copyright©2016 NTT corp.All Rights Reserved. 値による条件分岐の例 - Imperative
  • 24.
    24Copyright©2016 NTT corp.All Rights Reserved. 値による条件分岐の例
  • 25.
    25Copyright©2016 NTT corp.All Rights Reserved. • Reactive APIの戻り値 • Functional Style の推奨 • 条件分岐 • テスト⾟い問題 アウトライン
  • 26.
    26Copyright©2016 NTT corp.All Rights Reserved. テスト⾟い問題 • もちろんテストはRedに…? • ならない! • ⾮同期の罠 メインスレッド ⾮同期スレッド この仕事頼む! 任せろ! 任務完了… ちょ待てよ
  • 27.
    27Copyright©2016 NTT corp.All Rights Reserved. CountDownLatch • 他のスレッドの終了を待つための仕組み • Reactor特有のクラスではない • java.util.concurrent.CountDownLatch メインスレッド ⾮同期スレッド CountDownLatchを1にセット 任せろ! この仕事頼む! CountDownLatchが 0になるまで待つよ CountDownLatchを カウントダウンするよ 終わった! 完了!
  • 28.
    28Copyright©2016 NTT corp.All Rights Reserved. 同期による問題解決 CountDownLatchを使って,⾮同期スレッドの処理が済むのを待つ すべてのテストにブロックの処理書くのは⾟すぎる…
  • 29.
    29Copyright©2016 NTT corp.All Rights Reserved. TestSubscriber 同期させるためのコードを⾃分で書く必要がない
  • 30.
    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 では依然準備中…
  • 31.
    31Copyright©2016 NTT corp.All Rights Reserved. • Reactive APIの戻り値 • 必ず Mono か Fluxを返そう • Functional Style の推奨 • ⼤きな処理は⼩さな関数を組み合わせて作る • 条件分岐 • エラーやEmptyを特別扱いするためのメソッドがある • if⽂を使っても問題ない • テスト⾟い問題 • TestSubscriber待機…? まとめ
  • 32.
    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/ 参考⽂献