15 min/d

ぼうずやのにっき

bouzuya/b-o-a 0.8.0 をつくった

bouzuya/b-o-a 0.8.0 をつくった。

b-o-a 0.8.0 は handler の方針を変更し、handler chain を非推奨にした。handler chain は handler の出力を次の handler の入力にすること。handler chain の例は次のとおりだ。

import { run, A, O } from 'b-o-a';
import { init as init1 } from 'handler1';
import { init as init2 } from 'handler2';

const main = (): void => {
  run((action$: O<A<any>>, options: any): O<A<any>> => {
    // handler chain
    const a1$ = init1().handler(action$, options);
    const a2$ = init2().handler(a1$, options); // a1$ を渡す
    return app(a2$, options); // a2$ を渡す
  });
};

0.7.x までの handler は handler chain を前提とし、各 handler は自身の関心のある action を処理するほかに、それ以外の action を次に流すようにしていた。こうしないと、handler chain によって、そこで関心外の action をすべて filter してしまうからだ。

0.8.0 からの handler は handler chain を前提とせず、各 handler は自身の関心のある action を処理するが、それ以外の action を次に流さなくなった。必要なら次のようにすれば従来と同じ挙動になる。

const a$ = O.merge(
  action$.filter(...),
  init().handler(action$, options)
);

そもそも、なぜ handler chain が問題になるのか。

handler chain を想定するとすべての action$ が run(handler, options)handler を通らなくなり、循環しない点が問題だ。handler の chain をたどる過程で知らぬうちに action が間引かれて、循環しないのは危険だ。たとえば、すべての action を logging することが難しくなるし、それは replay などの実装を困難にする。

新しい handler の方針は単純だ。すべての handler は自身の関心のある action だけを処理すべきで、それ以外は無視すべきだ。すべての handler に無視されれば循環しなくなるので、無限に循環する心配はない。すべての action に共通の処理をはさみたければ、そこだけを chain にし、ほかをすべて O.merge(handler(), handler(), ...) のようにすべきだ。

なぜ、いままで気づかなかったのかはよく分からない。