Your SlideShare is downloading. ×
Clean Architectureで設計してRxJSを使った話
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Clean Architectureで設計してRxJSを使った話

81
views

Published on

歌舞伎座.tech#7「Reactive Extensions」での発表資料 …

歌舞伎座.tech#7「Reactive Extensions」での発表資料
http://kbkz.connpass.com/event/12597/

Published in: Engineering

0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
81
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
3
Comments
0
Likes
2
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. kondei twitter: @_kondei Clean Architectureで設計して RxJSを使った話
  • 2. 何に使ったの? ニコニコ生放送の、動画広告 …を配信するための、運営ツール (ユーザーには見えない)
  • 3. 素のTypeScriptで実装するか…
  • 4. ▂▅▇█▓▒░(’ω’)░▒▓█▇▅▂ うわああああああ
  • 5. 要件が複雑 • 機能が多い • 13個の細かい機能 • 3つのAPIを叩く • 状態が多い • 非同期処理が多く、イベント発火の時系列が複雑 • ツールの有効無効の切り替え • カウントダウン表示 & 終了時に色んな処理 • ツールをクリックしたら10秒おきに動画広告状態取得開始 • 色んな表示を10秒おきに取る動画広告状態に同期 • …
  • 6. • 非同期処理のリッチなライブラリを使う • アーキテクチャは何でもいいが、「プレゼンテー ションとドメインの分離」原則を適用する • データの流れと依存関係を単方向にする • Fluxや、ちゃんとしたMVCのように • 可能なかぎりReactiveに書く • Interactiveに操作しだすと、どこから変更されるのか分か らない こうしないと書ける気がしない
  • 7. 何を採用しよう?
  • 8. RxJS 採用 • jQueryと協調する • TypeScriptですぐに使えるFRPライブラリ • IE8対応してる • 社内で使用実績があった(nicocas) • (のちのち書いたFRPライブラリ比較) • http://qiita.com/kondei/items/17e5d4867a0652911e52
  • 9. クリーンアーキテクチャ 採用 • 厳密に適用すれば、依存関係は一方向になる • DDDを適用したほうが機能拡張に強いはず • サーバサイドはDDDだし… http://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html
  • 10. 設計
  • 11. ControllerGateway Presenter Domain Model Usecase View (html) API <I> Gateway <I> Controller External Interface Interface Adapters Application Business Rules Enterprise Business Rules
  • 12. ControllerGateway Presenter Domain Model Usecase View (html) API <I> Gateway <I> Controller External Interface Interface Adapters Application Business Rules Enterprise Business Rules 入力イベントをObservable として公開 APIレスポンスを Observableとして公開
  • 13. ControllerGateway Presenter Domain Model Usecase View (html) API <I> Gateway <I> Controller External Interface Interface Adapters Application Business Rules Enterprise Business Rules 入力イベントをObservable として公開 APIレスポンスを Observableとして公開 Domain Modelや入出力を利用して ユース ケースのドメインロジックを実現し、 Observableとして公開
  • 14. ControllerGateway Presenter Domain Model Usecase View (html) API <I> Gateway <I> Controller External Interface Interface Adapters Application Business Rules Enterprise Business Rules 入力イベントをObservable として公開 APIレスポンスを Observableとして公開 Domain Modelや入出力を利用して ユース ケースのドメインロジックを実現し、 Observableとして公開 UsecaseやControllerの Observableを利用して プレゼンテーションロジックを実現
  • 15. Presenter は何をしてるの 1. Controller や Usecase らの Observable を入力 2. ストリーム(イベント)を操作・合成 3. Subscribe 内で DOM 操作 表示要素が、ユースケースにReactする
  • 16. どういう流れでストリーム構築するの 1. TypeScriptだったので、全てconstructorで構築 要するに、ストリームを1度だけ宣言することが重要 2. 後述のInitializerで、依存関係の無い順に初期化
  • 17. こんなInitializerをHTMLから呼んだ export class Initializer { constructor(private apiUrl: string, private $hogeElement: JQuery) { // 入力 var controller = new Controller($hogeElement); var apiClient = new ApiClient(apiUrl); // ユースケース var usecase1 = new Usecase1(controller, apiClient); var usecase2 = new Usecase2(controller, apiClient); var usecase3 = new Usecase3(controller); // 出力 var presenter1 = new Presenter1(controller, usecase1, …); var presenter2 = new Presenter2(controller, usecase1, …); } }
  • 18. 実装後しばらくして気づいた
  • 19. MVI アーキテクチャに似てた Model Intent View 入力: Modelからのデータイベント 責務: プレゼンテーションロジック 出力: Modelのレンダリングや、生 のユーザー入力イベント 入力: Intentからのユーザーインタラクションイベント 責務: ビジネスロジック 出力: データイベント 入力: Viewからの生のユーザー入力イベント 出力: Modelフレンドリーなユーザーインタラ クションイベント(Observable)
  • 20. MVI とは • 完全リアクティブなMVC • 提唱者によるフレームワークがある • staltz/Cycle.js • RxJSを活用している • Flux/Reactで使ってるEvent emitterは単機能すぎるという意見らしい http://futurice.com/blog/reactive-mvc-and-the-virtual-dom/
  • 21. クリーンアーキテクチャ 感想 今回の自分の設計では… • RxJS とうまく協調できた • MVIに近いものになり、その方が単純化できただろう • 設計力不足でドメインモデル貧血症になった • フロントエンドでは、動画広告というドメインモデルがフラ グ1個と同一性判定しか持たなかった • 動画広告案件のユビキタス言語も決めたが、ほぼサーバ側で しか使わなかった • この規模で依存関係の逆転は過度の抽象化だった
  • 22. 心残り jQueryでDOM操作した部分がInteractive感ある • MVVM のようなデータバインドでReactiveにできそう • http://webrxjs.org/ というRxJSのMVVMフレームワークもある • Cycle.jsでJSXで宣言的にDOM操作する例あり • https://github.com/ivan-kleshnin/cyclejs-examples
  • 23. RxJS だけの話
  • 24. RxJS 気をつけたこと • なるべくストリームの操作で済ませる • Subscribe を書く場所を絞る(今回は基本的にPresenter) • Subscribe 内で Subscribe しない • 副作用はSubscribeに書き、Doは極力避ける • ストリームの途中で副作用を書くと、分岐したら何の原因で 副作用が発生するかわからなくなる
  • 25. RxJS 気をつけたこと • Subjectをなるべく使わない。使える用途は、 • テスト用 • 非Observable → Observableのラッパ作るとき • 何らかの事情でObservableを拡張したいとき • (とはいえpublish/multicast等が似たようなことしているので必 要ないかも) • 子ストリームの結果を親へ流したくて、副作用でデータを受 け付けて流すストリームを提供したいとき
  • 26. RxJS 気をつけたこと • OnNextを避ける • 明示的に書くと手続き型になるため • 手続き型に書いてるなら使ってもいいかも(ただしその場合 はクラス内に隠蔽し、外に公開するならasObservableをかま せる)
  • 27. RxJS 気をつけたこと • Observable を公開するときはHot変換しておく • Coldのまま公開して分岐すると、Subscribe のたびにその Observable内の処理が走る
  • 28. RxJS 気をつけたこと • 知見の共有! • 使い手が少ないとレビュー依頼にも困る • slackの #rx 活用 • 社内ConfluenceにRxの知見まとめページを作った • 他、Qiitaに記事を上げたりなど
  • 29. RxJS ハマったこと • 現象 • APIリクエストを含むストリームを関数で定義して公開した ら、Subscribeの回数分APIリクエストが走った • 理由 • Subscribeのたびに関数が呼ばれ、ストリームが構築され、 APIリクエストも走った • 対策 • ストリームはコンストラクタで定義してローカルメンバ変数 に代入しておき、それを返すだけの関数を提供すべし
  • 30. RxJS ハマったこと • 現象 • Cold Observableを Hot変換してrepeat()したら、Cold Observable の終了後に Call stack overflow • 理由 • 終了した Cold が Completed を流し、repeat()が再 Subscribeする、を無限に再帰 • 対策 • Cold ObservableをHot変換したらrepeat()しない • Rx の仕様かも? Special Thanks: wilfrem さん、toRisouP さん
  • 31. RxJS ハマったこと • 現象 • just(jQuery.val()) を返す関数を作ったら、undefined が 流れてきた • 理由 • just でストリーム作るタイミングで jQuery.val()が undefined だった • 対策 • defer(() => just(JQuery.val())) のように、遅延評価
  • 32. RxJS ハマったこと • 現象 • 定期的な fromPromise を起点にした処理が、IEでは2度目の リクエスト以降動作しなかった • 理由 • IE は Ajax の GET をキャッシュするせいで、2度目以降は ストリームが発火しない • 対策 • cache: false 追加 • http://qiita.com/kondei/items/99648a07418793d5f50b
  • 33. RxJS ハマったこと • 現象 • IE8でエラー • 理由 • IE8の予約語に「do」があり、do()と重複 • 対策 • RxJSのGitHubドキュメント見て、別名メソッドに変える • do → tap • catch → catchException
  • 34. RxJS 使って何が良かった? • 複雑な処理を、他の複数の処理の起点にできた • Observableの公開・合成 最高に便利! • 素早く機能追加できた • ストリームに関数1個挟むだけだったり • 時間の概念を含む実装が楽だった • 定期的リクエスト • 複数の終了条件を持つカウントダウンも簡単に private countdownStream(remain: number) { Rx.Observable .timer(0, this.countdownSpan) .map(r => { return remain - r + 1; }).takeWhile(r => { // 0秒で終了 return r >= -1; }).takeUntil(動画広告状態が非再生中); }
  • 35. RxJS 使わなかったら? • 独自イベントの乱舞 • コールバック地獄
  • 36. 総括 • RxJS と Clean Architecture を良く協調させれた • RxJS を全面的に使う際のアーキテクチャは、大抵は MVIの方が単純で良い • RxJS は罠が多いので知見を共有すべし
  • 37. リンク • クリーンアーキテクチャ 初出記事 • http://blog.8thlight.com/uncle-bob/2012/08/13/the- clean-architecture.html • クリーンアーキテクチャについて書いた記事 • http://qiita.com/kondei/items/41c28674c1bfd4156186 • RxJS について書いた記事 • http://qiita.com/kondei/items/99648a07418793d5f50b • http://qiita.com/kondei/items/17e5d4867a0652911e52