Rx がなぜ良いか

プログラミングでは何度も同じ実装をせずに再利用することが大事だ。そして再利用できるプログラムを書くためには、なるべく一般化することが大事である。プログラミング言語自体もその一種と考えることができる。例えば if のような条件分岐も、jmp 命令などを使わずに if と書くだけで実現できる。プログラマはわざわざ if を再実装しなくて済む。

非同期処理についてはどうだろうか。私があるライブラリで見た非同期制御のコードでは、while の中でロードの進捗を返す関数を毎回呼び出し、その結果が 100 になれば処理が終了したと言うような判断を行っていた。だがしかし非同期処理で誰もが必要な処理についてわざわざそんなことをしたくないだろう。

非同期処理でどんな言語でもよく用いられるのがコールバック関数である。処理が終了したときに呼ばれる関数を渡して、単一の非同期処理を行うだけなら問題はないが、例えば2つの非同期処理を実行してその両方の結果を待つといったような処理を考えると、フラグなどを使って実現することができるが、このようなよくある処理を自分で実装しないことがプログラミングには大事だろう。

近年では、async/await といった非同期処理のための構文があるものも多いが、Promise についても言えることだが、これらは1つのパラメータをとって1つの結果を非同期で返すと言うものにしか使うことができない。例えばテキストのログを処理するプログラムがあったとして、これを逐次的に処理してファイルに書き込むようなプログラムを実装するには、async/await だけでは足りないだろう。Reactive Extensions ではストリームと言う概念によってデータが非同期で流れてくることを表現している。

プログラミングではなるべく何回も同じこと繰り返さない DRY が大事とされている。しかし、汎用的なプログラム作成というのは難しい。あらゆるところで、特定の機能を実現するライブラリが用いられている。

今日のアプリケーションでは、非同期処理がいろいろなところに現れる。例えば2つの API から情報をとってきてそれを結合するといった処理では、リクエストの完了を待ち合わせる必要がある。これを実装することは難しくないが、避けるべきだ。なぜなら自前で実装されたプログラムは他人とってはすごく読みづらいものであり、メンテナンスが難しい。しかし Rx のメソッドをただ1つ使うとなれば、それは Rx を知っている人にとってはすごくわかりやすい。また、Rx 自体のドキュメントが充実しているため最終的にまるでわからないといった事態には陥いらないだろう。わざわざリクエストを待つだけの処理に対して、どれだけ充実したドキュメントを用意できるだろうか。

逆に言えば Rx を使う上で非常に重要なのが、自分で非同期処理を実装しないということだ。例えば先ほど挙げたような例で、片方の API のリクエストが完了した段階でフラグを立てて、もう片方のリクエストが完了したときにそのフラグをチェックするといったような処理を書くことは Rx を使う上では全く推奨できない。このような処理を代行するためのライブラリなのだから。しかし難しい点もある。自分で実装しないためには、Rx が提供する機能をたくさん知っている必要がある。Rx には沢山のメソッドが用意されており、それらをすべて熟知することは容易ではない。また例えば、map と flatMap の違いや Hot/Cold 変換、RxSwift であれば dispose bag のような独特のインスタンスの管理方法などについて理解する必要がある。

銀の弾丸ではないのでチームの状況をよく考えて選択するべきだろう。

(2020年3月3日に運転中に音声入力で書いた原稿を加筆修正したもの)


この記事が気に入ったらサポートをしてみませんか?