Observable Everywhere - Rxの原則とUniRxにみるデータソースの見つけ方

64
Observable Everywhere Rx の原則と UniRx にみるデータソースの見つけ方 2015/04/16 Yoshifumi Kawai - @neuecc

Transcript of Observable Everywhere - Rxの原則とUniRxにみるデータソースの見つけ方

Page 1: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

Observable EverywhereRxの原則とUniRxにみるデータソースの見つけ方

2015/04/16Yoshifumi Kawai - @neuecc

Page 2: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

@neuecc - Who, Where, When

2009/04linq.js – LINQ to Objects for JavaScript

https://linqjs.codeplex.com/

この頃からずっとLINQを追いかけてる

2009/09/04

最初のRx記事、以降現在まで70以上は書いてる

http://neue.cc/category/programming/rx/

2011/04~

Microsoft MVP for .NET(C#)

野良C#エヴァンジェリスト(現在も継続中)

Page 3: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

@Work, @LINQ

2012/10~

株式会社グラニ取締役CTO

「神獄のヴァルハラゲート」「モンスターハンターロアオブカード」

サーバー/クライアント共に「最先端C# 技術を使った」ゲーム開発

C# 5.0 + .NET Framework 4.5 + ASP.NET MVC 5 + Unity

2014/04/19

UniRx最初の公開 - https://github.com/neuecc/UniRx

現在☆286, ver 4.8.0

2014/09/24

LINQ to BigQuery - https://github.com/neuecc/LINQ-to-BigQuery/

未だにLINQへの関心は衰えずといったところ

Page 4: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

Agenda

Page 5: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

せつめい

基本的には言語非依存の説明です

RxJavaの人もReactiveCocoaの人もWelcome

サンプルコードはC#になりますので適宜補完してください

Rxの基本原則などを紹介

衒学趣味を蹴っ飛ばして実用的な意味合いを探る

UniRxを例にRx利用時のデータソースの実例を紹介

自分の言語、自分のプラットフォームでも応用効くはず

Page 6: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

OnNext* (OnError | OnCompleted)?

Page 7: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

The grammar of messages

OnNext* (OnError | OnCompleted)?

日本語でおk

OnNextがゼロ回以上の後に

OnErrorもしくはOnCompletedが一回来る(もしくはどちらも来ない)

public interface IObserver<in T>{

void OnCompleted();void OnError(Exception error);void OnNext(T value);

}

Page 8: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

foreachで考えてみる; OnNext

foreach (var x in sequence){

OnNext(x);}

OnNext*

空の場合はOnNextは一度も呼ばれないのでOnNext*

Page 9: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

foreachで考えてみる; OnCompleted

foreach (var x in sequence){

OnNext(x);}OnCompleted();

OnNext* (OnCompleted)?

もしsequneceが無限シーケンス(例えばunfold)だったら

OnCompletedまで行かないので

OnNext * (OnCompleted)?

Page 10: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

foreachで考えてみる; OnError

try{

foreach (var x in sequence){

OnNext(x);}

}catch (Exception ex){

OnError(ex);// RxでonErrorをハンドルした場合// 再スローはない、これはあくまで再現

throw;}OnCompleted();

OnNext* (OnError | OnCompleted)?

もし途中で例外が起きたらOnCompletedは呼ばれずOnErrorだけが呼ばれることになるので

OnNext * (OnError | OnCompleted)?

Page 11: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

意味が通る!でも、なんで?

Page 12: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

IEnumeratorから考える

public interface IEnumerator<out T>{

T Current { get; } // 現在の要素bool MoveNext(); // 次の要素があるか確認しCurrentにセット

}

Page 13: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

分解

public interface IEnumerator<out T>{

T Current { get; }bool MoveNext() throws Exception; // (C#にthrowsはないけどネ)

}

public interface IEnumerator<out T>{

T Current { get; }true|false|Exception MoveNext();

}

MoveNextを分解するとtrue/false/Exceptionのどれかを返す

Page 14: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

集約

public interface IEnumerator<out T>{

T Current { get; }bool MoveNext() throws Exception; // (C#にthrowsはないけどネ)

}

public interface IEnumerator<out T>{

T Current { get; }T|void|Exception GetNext();

}

trueの時Tを、falseの時voidを返すと考えてCurrentも集約

Page 15: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

そして(何故か)反転させる

public interface IEnumeratorDual<in T>{

void GotNext(T|void|Exception);}

public interface IEnumerator<out T>{

T|void|Exception GetNext();}

Page 16: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

3つにちゃんとバラして

public interface IEnumeratorDual<in T>{

void GotNext(T);void GotNothing(void);void GotException(Exception);

}

public interface IEnumeratorDual<in T>{

void GotNext(T|void|Exception);}

Page 17: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

あら不思議、IObserver<T>が!

public interface IEnumeratorDual<in T>{

void GotNext(T);void GotNothing(void);void GotException(Exception);

}

名前を変えれば出来上がり

public interface IObserver<in T>{

void OnNext(T value);void OnCompleted();void OnError(Exception error);

}

Page 18: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

IEnumerableのほうも勿論public interface IEnumerable<out T>{

IEnumerator<T> GetEnumerator();}

Page 19: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

IEnumerator<T> : IDisposablepublic interface IEnumerable<out T>{

IEnumerator<T> GetEnumerator();}

public interface IEnumerable<out T>{

IDisposable|IEnumerator<T> GetEnumerator();}

IEnumerator<T> : IDisposable

Page 20: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

public interface IEnumerableDual<out T>{

IDisposable SetEnumeratorDual(IEnumeratorDual<T>);}

public interface IEnumerable<out T>{

IDisposable|IEnumerator<T> GetEnumerator();}

当然のように(何故か)逆にする

Page 21: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

public interface IEnumerableDual<out T>{

IDisposable SetEnumeratorDual(IEnumeratorDual<T>);}

あら不思議、IObservable<T>が!

public interface IObservable<out T>{

IDisposable Subscribe(IObserver<T> observer);}

名前を整えて出来上がり

Page 22: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

Mathematical Dual

双対

なるほどわからん

ふかーい関連性がある、ぐらいでいいんじゃまいか

実用的な意味では、OnNext* (OnError | OnCompleted)?だけ覚えればいい

同じように見なすことができる、という発見

IEnumerable<T> = イテレータパターン

IObservable<T> = オブザーバーパターン

一見無関係の2つのデザインパターンに見つけた深い関連性

イテレータのためのLINQがオブザーバーにも同じように適用できる発見

Reactive Extensions = LINQ to Events / LINQ to Asynchronous

Page 23: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

Pull(Interactive) vs Push(Reactive)

DataSource

(IEnumerable<T>)

Action

値の要求(Pull)

DataSource

(IObservable<T>)

Action

値の送信(Push)

Page 24: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

Length or Time

IEnumerable<T> length

IObservable<T> time

event

async

IE<T>

イベント(や非同期)を時間軸に乗ったシーケンスと見なすことができる

Page 25: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

Same Atmosphere

var query = from person in sequencewhere person.Age >= 20select person.Name;

foreach (var item in query){

OnNext(item);}

var query = from person in sequencewhere person.Age >= 20select person.Name;

query.Subscribe(item =>{

OnNext(item);});

IEnumerble<T> IObservable<T>

コレクション処理(filter/map)が超強力で有益なのは既知の話。それと同じように書ける、同じような挙動を取るということが注意深くデザインされている。

これがRxの革命的なポイントであり普及の一助となった

Page 26: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

Asynchronous Futures

Page 27: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

Synchronous Asynchronous

Sin

gle

(1)

Mu

ltip

le(*

)

var x = f(); var x = await f();

var query = from person in sequencewhere person.Age >= 20select person.Name;

foreach (var item in query){

OnNext(item);}

var query = from person in sequencewhere person.Age >= 20select person.Name;

query.Subscribe(item =>{

OnNext(item);});

IEnumerble<T> IObservable<T>

Func<T> Task<T>

Page 28: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

Synchronous Asynchronous

Sin

gle

(1)

Mu

ltip

le(*

)

var x = f(); var x = await f();

var query = from person in sequencewhere person.Age >= 20select person.Name;

foreach (var item in query){

OnNext(item);}

var query = from person in sequencewhere person.Age >= 20select person.Name;

query.Subscribe(item =>{

OnNext(item);});

IEnumerble<T> IObservable<T>

Func<T> Task<T>

FutureとかPromiseとか言われるアレの

C#での表現

Page 29: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

C# 5.0での非同期事情

C# 5.0では単発の非同期処理は全てTask<T>を返す

async/awaitという言語構文でのサポートが圧倒的に大きい

Task<T>にawaitするとTが取れるし、.NET Frameworkで全面的に非同期APIが追加された

Task is Observable, Observable is Awaitable

相互変換可能(Taskは長さ1のIObservable、IObservableはLastを取得してTaskに変

換できる)なので、適宜必要な局面で変換

Before async/await

専用構文がないTaskだけとの比較だとRxのほうが圧倒的に使いやすかった

というわけで、他言語においても事情は同じになるかな、と

専用構文が入ればそちらに寄って、それまではRxが使う上では強いはず

Page 30: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

What is UniRx?

Page 31: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

Welcome to the Reactive Game Architecture!

https://github.com/neuecc/UniRx Unity用のReactive Extensions実装(.NET用のRxはUnityで動かないので自前で実装)

Page 32: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

Official(?) ReactiveX Family

http://reactivex.io/ReactiveX公式サイトのLanguagesにラインナップされています(現状、非公式Rxでは唯一)

Page 33: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

CoreLibrary

Framework Adapter

Rx.NET

RxJS

RxJava

RxAndroidReactiveUI

ReactiveProperty

Page 34: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

CoreLibrary

Framework Adapter

UniRxは全部入り(多分ReactiveCocoaとかもそうでしょうけど)

Port of Rx.NET

MainThreadSchedulerObservableTriggers

ReactiveProperty

Page 35: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

Observable Everywhere

Page 36: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

データソースを見つけよう

何はともあれObservableの源流が必要

使い方は後からついてくる

通常のLINQ(to Objects)も何がシーケンスとみなせるか(DOMの

Traverseはシーケンスになる、DatabaseのRowはシーケンスとみな

せる、などなど)がまず最初にある

シーケンスを作ろう

シーケンスのように見なせるものがあれば、そこにLINQはある

見なせそうで見なせない、ありそうでないものがあれば、作りだ

そう、そうすればそこにLINQ(to Objects/to Events = Rx)が現れる

Page 37: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

Push Event Stream

Event Processing

Interactive/Visualize

Page 38: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

Statndard Static Generators

Range, Repeat, ToObservable

OnNext{n} (OnError | OnCompleted)?

Return

OnNext (OnError | OnCompleted)?

Empty

OnCompleted

Never

()

Throw

OnError

単体ではそう使うこともない感じですが、何かと組み合わせていく感じ

.Concat(Observable.Never)で、終了を抑止する(OnCompletedは飛ばさない、あるいは他のオペレータが飛ばす)、的な使い方ができる

Page 39: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

AsyncCallback Converter

IEnumerator GetStringAsync(string url, Action<string> onCompleted, Action<Exception> onError);

Callback Hell!謎のIEnumerator(Unity固有事情)

IObservable<string> Get(string url);

Callback to IObservable<T>

UniRxは組み込みの通信メソッドとしてObservableWWW.Get/Postメソッドなどを予め用意してあるので、ユーザーはすぐに非同期をRxで扱える

Page 40: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

But...

あれ、一緒……?

ObservableWWW.Get("http://hogemoge").Subscribe(Action<string>, Action<Exception>)

StartCoroutine(GetStringAsync("http://hogemoge", Action<string>, Action<Exception>))

Page 41: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

GetStringAsync("http://hogemoge", nextUrl =>{

GetStringsAsync(nextUrl, finalUrl =>{

GetStringsAsync(finalUrl, result =>{

/* result handling */}, ex => { /* third error handling */ });

}, ex => { /* second error handling */ });}, ex => { /* first error handling */ });

Callback Hellネスト地獄による圧倒的な見通しの悪さ

エラーハンドリングの困難(try-

catchで囲んでも意味が無い)

ObservableWWW.Get("http://hogemoge").SelectMany(nextUrl => ObservableWWW.Get(nextUrl)).SelectMany(finalUrl => ObservableWWW.Get(finalUrl)).Subscribe(

result => { /*result handling */ },ex => { /* error handling */ });

ネストを一段に抑えるパイプライン統合のエラー処理

Page 42: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

Composability

var query = from nextUrl in ObservableWWW.Get("http://hogemoge")from finalUrl in ObservableWWW.Get(nextUrl)from result in ObservableWWW.Get(finalUrl)select new { nextUrl, finalUrl, result };

var parallelQuery = Observable.WhenAll(ObservableWWW.Get("http//hogehoge"),ObservableWWW.Get("http//hugahuga"),ObservableWWW.Get("http//takotako"));

var parallelQuery = Observable.WhenAll(ObservableWWW.Get("http//hogehoge"),ObservableWWW.Get("http//hugahuga"),ObservableWWW.Get("http//takotako"))

.Timeout(TimeSpan.FromSeconds(15));

var incrementalSearch = userInput.Throttle(TimeSpan.FromMilliseconds(250)).Select(keyword => SearchAsync(keyword)).Switch();

前の結果を保持したままの直列処理

並べるだけで済む並列処理

メソッドを足すだけのTimeout付与

ユーザー入力など他のIObservableとの自然な融和と、複雑なPruning

Page 43: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

UIEvent Converter

Button

IObservable<Unit>

InputField

IObservable<string>

Toggle

IObservable<bool>

Slider

IObservable<float>

var incrementalSearch = input.OnValueChangeAsObservable().Throttle(TimeSpan.FromMilliseconds(250)).Select(keyword => SearchAsync(keyword)).Switch();

from InputField

toggle.OnValueChangedAsObservable().Subscribe(x => button.interactable = x);

ToggleのON/OFFでボタンの有効/非有効切り替え

Page 44: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

ObservableTriggers

衝突 = IObservable<Collision>

cube.OnCollisionEnterAsObservable().Subscribe();

カメラに入る = OnBecameVisibleAsObservable() = IObservable<Unit>

カメラから出る = OnBecameInvisibleAsObservable() = IObservable<Unit>

などなど、あらゆるインタラクションが全てIObservableになる

Page 45: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

Lifecycle as Observable

frame(time)

OnDestroyAsObservable = (OnNext{1} OnCompleted)

ゲームループは毎フレーム(60fpsなら1/60秒)毎にメソッドが呼びだされる

Observable.EveryUpdate().Subscribe(); // IObservable<long>

Page 46: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

MultiThreading

Rx = Observable + LINQ + Scheduler

Observable.Start(() =>{

/* なにか重い処理 */

return "hogemoge";}, Scheduler.ThreadPool).ObserveOn(Scheduler.MainThread) // MainThreadに戻す

.DelaySubscription(TimeSpan.FromSeconds(3), Scheduler.MainThreadIgnoreTimeScale)

.Subscribe(x => ui.text = x); // UIパーツはメインスレッドからじゃないと触れない

Schedulerは時空魔法の、時(AbsoluteTime/RelativeTime)と空間(実行スレッド/SynchronizationContext)をコントロール

Page 47: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

Polling

ポーリングはIObservableと「見なせる」

IObservable<string> WatchFile(string path){

return Observable.Interval(TimeSpan.FromSeconds(5)).Select(_ => File.ReadAllText(path));

}

IObservable<Notification<Unit>> Ping(string path){

return Observable.Interval(TimeSpan.FromSeconds(5)).SelectMany(_ =>

ObservableWWW.Get("http://ping").Timeout(TimeSpan.FromSeconds(1))).AsUnitObservable().Materialize();

}

Page 48: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

EveryValueChanged

更に踏み込んで、値変更を常時監視する黒魔法化

原理はゲームループのUpdate監視による毎フレームチェック

常に必ず呼ばれるから監視コストが相対的に低い(ゲームエンジンならでは)

生存期間管理

無限監視は危険なので、監視対象の生存具合をチェック

GameObjectなら破壊されていたら監視終了

C#オブジェクトなら、WeakReferenceで参照保持し、GCされてたら監視終了

// Position(x,y,z)が変化したら通知するIObservable<Vector3>

this.ObserveEveryValueChanged(x => x.transform.position).Subscribe(x => Debug.Log("poistion changed:" + x));

Page 49: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

Logs are EventStream

ログはInProcessにおいてもStreamとして扱えるべき

logger(“Player”)

logger(“Monster”)

logger(“Network”)

logger(“ItemResolver”)

ObservableLogger.Listener

(IObservable<LogEntry>)

SubscribeToLogConsole

SubscribeToInGameDebugWindow

SubscribeToNetWorkLogStorage

Page 50: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

EventAggregator/MessageBroker

InProcessのMessageBus(名前はなんでもいいや)

先のObservableLoggerと同じ図式

中央がIObservable<T>なら

購読= IObservable<T>.Subscribe()

解除= subscription.Dispose()

Page 51: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

最も単純な(しかし便利な)実装

public static class MessageBroker{

public static void Publish<T>(T message){

Notifier<T>.Instance.OnNext(message);}

public static IObservable<T> Receive<T>(){

return Notifier<T>.Instance.AsObservable();}

static class Notifier<T>{

public static readonly Subject<T> Instance = new Subject<T>();}

}

型(<T>)でフィルタされるグローバルに通知可能な何か、と考える

送信側:

MessageBroker.Publish(new HogeEvent())

受信側:

MessageBroker.Receive<HogeEvent>()

Page 52: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

Model-View-Whatever

Page 53: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

M-V-Hell

MVVVVVV

Page 54: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

M-V-VM

DataBinding!

Page 55: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方
Page 56: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

バインディングに必要なもの

バインディングエンジン

Reactive Extensionsはバインディングエンジン「ではない」

RxでViewに何か処理するにはViewを知らなければならない

Unityにバインディングエンジンはない

作るか諦めるか

どうしても必要なら作るしかない

私はMVVMを選ばないことを選んだ

Unityにおいては(Rxがあれば)そこまで必要ではないと判断した

Page 57: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

Model-View-Presenter

DataBindingがないのでViewModelのかわりに

PresenterがViewを直接弄り、イベントを受け取る

Rxで各レイヤーを繋げてしまえば見通しよく構築可能

Page 58: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

NotificationModel

Modelは通知可能でなければならない

// 変更通知付きなモデル

public class Enemy{

// HPは変更あったら通知して他のところでなんか変化を起こすよね?

public IReactiveProperty<long> CurrentHp { get; private set; }

// 死んだら通知起こすよね?

public IReadOnlyReactiveProperty<bool> IsDead { get; private set; }

public Enemy(int initialHp){

// 死んだかどうかというのはHPが0以下になったら、で表現できる

CurrentHp = new ReactiveProperty<long>(initialHp);IsDead = CurrentHp.Select(x => x <= 0).ToReadOnlyReactiveProperty();

}}

Page 59: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

ReactivePropertypublic class ReactivePresenter : MonoBehaviour{

// ViewからのイベントをUIEventAsObservableで購読

Button button;Text textView;

// ModelからのイベントをReactivePropertyで購読、SubscribeでViewにUpdate

Enemy enemy;

// 宣言的なUI記述

void Start(){

// ボタンクリックでHPを減らす

button.OnClickAsObservable().Subscribe(_ => enemy.CurrentHp.Value -= 99);

// その変更を受けてUIに変更を戻すenemy.CurrentHp.SubscribeToText(textView); // とりあえず現在HPをTextに表示

// もし死んだらボタンクリックできないようにする

enemy.IsDead.Select(isDead => !isDead).SubscribeToInteractable(button);}

}

ReactivePropertyは通知付きモデルの作成を補助値自体が変更をIObservable<T>として通知

Page 60: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

Model-View-(Reactive)Presenter

Page 61: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

not databinding but databinding

データバインディングっぽい

Rxの力で、かなりそれらしい感触になる

マクロがあればもっと整形できそうだけどC#はマクロないので

別にそこまでは必要じゃない

無理しない

やはりゲームなのでパフォーマンスの読みやすさは必須

バインディングエンジン作成は一朝一夕でできない、それよりMV(R)Pはシンプ

ルな、というか中間レイヤーはなにもないので挙動も読みやすくオーバヘッド

もない

既に実績あるバインディングエンジンがあるなら、それに乗っかればいい

ReactivePropertyはModelの作成を補助するのでMVVMのMやVMのレイヤーで十分使える

Page 62: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

Conclusion

Page 63: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

資料紹介

Event processing at all scales with Reactive Extensions

http://channel9.msdn.com/events/TechDays/Techdays-2014-the-

Netherlands/Event-processing-at-all-scales-with-Reactive-Extensions

現時点でのRx入門の決定版といえる素晴らすぃVideo

Bart氏は現在はMicrosoftのPrincipal Software Engineer(偉い)

Cloud-Scale Event Processing Using Rx

http://buildstuff14.sched.org/event/174c265e4ec350bd2e005b59bce0275e

激烈にAdvancedな内容

IReactiveProcessingModel, SubjectのDuality, 次世代のRx(3.0)などなど

更なる未来を見据えた内容なので是非一読を

Page 64: Observable Everywhere  - Rxの原則とUniRxにみるデータソースの見つけ方

まとめ

LINQ to Everywhere

Reactive Extensions is not only Asynchronous

Reactive Extensions is not only Data-Binding

Observable Everywhere

データソースさえ見つかれば、そこにRxはある

あとは無限の合成可能性を活かせばいい!

まず、データソースを探しだしてください