読者です 読者をやめる 読者になる 読者になる

Meteorが見せるIsomorphicなDBとリアクティブな開発モデル

最近、Meteorを試して見てます。これはちょっとスゴイ。正直、当時Railsに受けたのと同じ興奮がある。

Meteorの説明は「リアルタイムWebアプリケーションフレームワークMeteorについて」あたりが分かりやすいので、こちら参照。

実は、2012年の公開時から存在は知ってたんだけど、チュートリアル見たくらいで特に興味はありませんでした。 しかし、今は違います。それは主にスマホアプリの開発にかなりの威力を発揮しそうだと気づいたからです。

まず、なんで公開時にあまり興味がなかったかですが、そもそもRailsなど同レイヤーのWebアプリケーションの開発FWとして考えていました。

その場合

  • SPA
  • リアクティブな開発モデル
  • クライアントとサーバを同一コード(JS)で書ける
  • サーバサイドのDBをクライアントから透過的に呼び出せる(IsomorphicなDBモデル)

という特徴はせいぜいリアクティブな開発モデルがちょっと気になるくらいで、他はさほど気になりませんでした。 むしろ、クライアントコードとサーバサイドを同一でってのは初期のASPGWTはじめ多くのFWが目指したものの、そこまで流行らなかった印象だけがありました。 リアクティブプログラミングも気にはなるものの、私が当時書いていたWebアプリはさほどUIがリッチではなかったので、修正したコードが更新ボタン押さなくても反映されるのはスゴイな、という印象止まり。

SPAにはSEOの問題もついて回りますし、ざっくりフルスタック過ぎて密結合なシステムになりそうだなーと、むしろ悪い印象。

というわけで、さほど興味を引くものではなかったのですが、Meteor + PhoneGap/Cordovaと連携して使うことで、クライアントとサーバ(クラウド)のデータ同期というかアクセスモデルを超シンプルにしてくれると気づきました。

そもそも何が問題?

スマホ開発の課題をあげよ、と言われると人によって多くの課題が上がると思いますが、その一つにサーバサイドと連携したデータアクセスがあると考えています。

いろんなケースがあるかとは思いますが、サーバサイドと連携したアプリを書くときは全体として以下の様な構成にするとことが多いかと思います。

f:id:pascal256:20150112112438p:plain

図:モデル1

このモデル1のケースでは以下の様な問題があります。

  • モデルを一致させるためにサーバサイドとクライアントサイドに類似コードが大量のボイラーコードが発生する(+ REST周りのコードが必要)
  • Server DBとClient DBの同期が困難(安定したネットワークではないため不整合の吸収が必須)

クライアントサイドにデータを一切持たず、サーバサイドに直接アクセスすることで、同期の複雑さ等は解決できます。しかし、反面ネットワークに繋がってない時は利用できず、繋がってる時もレスポンスに影響が出るので使い勝手に影響がでます。

実際のシステムモデルはともかくとして、プログラム上はこんな感じでシンプルにアクセスしたい。

f:id:pascal256:20150112112457p:plain

図:モデル2

この場合、クライアントのDBは基本キャッシュになっていて、クライアントDBへの操作を行えば、サーバサイドにも自動的に反映。モデルのメタ情報も何らかの方法でサーバサイドと同期を取っておけばボイルコードが一気に減り、やる気も上がって生産性アップ! となります。

そう、Meteorはこのモデルを実現してくれてるんです。

MeteorにおけるIsomorphicなDBモデル

Meteorがサーバとクライアントを意識しないIsomorphicなDBモデルをどのように実現しているかですが、minimongoというmongodbのJS実装を使っていて、これをクライアントのキャッシュDBとして使っています。

ユーザへのレスポンスは基本的にminimongoの結果をまず返され、それと同時に投げているサーバサイドのリクエストをバックエンドで待つ。

この時、もしサーバサイドのmongodbとクライアントサイドのminimongoの結果が違った場合は、非同期でこっそり書き換えるという仕様。

厳密なデータ一貫性が必要なケースには使えないけれど、リアルタイムなデータを表示するレポート系ツールやチャットやSNSのような場合なら基本問題無いでしょう。

また、Meteorの場合、サーバサイドがnode.jsなので当然のようにモデルが共有されます。

Meteorがサーバサイドもクライアントサイドも同一のコードで書ける、という点は単に同じコードでvalidationロジックが実行出来る、というよりもモデルの共有ができるので、サーバサイドとクライアントサイドで違うビジネスロジック部分だけを意識すれば良いという点が大きいです。

IsomorphicなDBモデルとリアクティブプログラミング

Meteorの特徴はIsomorphicなDBモデルということに加えて、リアクティブプログラミングを採用している点も大きいです。

リアクティブプログラミングはExcelのように宣言的に関係を記述することでデータの変更による再計算を自動化する開発モデル。

GUIだとデータバインディングを利用したMVVMとかがその具体的な方法の認識。

この2つを組み合わせることでMeteorはリアルタイムアプリケーション--- 言い方を変えるとユーザ関連系などサーバサイドの頻繁な更新が伴うアプリケーションを非常にシンプルに書ける。

というのも、モデル1のような通常のシステム構成でchatのようなユーザ間連携があるシステムを作る場合

  1. クライアント側の書き込みのUIからモデルに値を渡す
  2. クライアントのモデルがサーバサイドのREST/IFをコールする
  3. REST/IFから受け取った値をサーバのモデルに渡す
  4. サーバのモデルはDBに値を書き込む
  5. サーバはDBの変更を別のクライアントに呼び出すモデルを実行(WebSocketではなくクライアントがポーリングしてるならクライアントにその実装がいる)
  6. 5で呼び出されたモデルはDBから値を取得してREST/IFに渡す
  7. クライアントはREST/IFから受け取った値をクライアントのモデルに値を渡す
  8. クライアントのモデルはUIに値を渡して変更する

という感じになります。FWによって記述量が変わるところはあっても、1から8の工程を明示的に何かしら記述をしないといけません。これは単純にサーバサイドもクライアントサイドもJSで書いたからといって変わるものではありません。

対してMeteorの場合は

  1. UIからクライアントのDBに書き込むモデルを作る
  2. モデルとクライアントのDBを紐付ける(※ モデルをJSONハードコーディングじゃなくてDBの戻り値にする)
  3. UIとモデルを紐付ける

これだけです。それぞれのステップでの記述量もかなり短くなるのですが、それ以前にステップが8個から3個に減っています。

これが実現できるのはIsomorphicなDBモデルなので、各クライアントは自分たちのローカルDBへの操作だけ意識すれば良く、かつリアクティブなので、データに変更があれば、UIにも自動的に反映されるからです。

この点が開発のシンプルさを激的に改善してくれる部分です。各工程のコストを小さくするのと、工程自体が無くなるのではたとえ1秒で終わることでも人間の意識としては結構違いますしね。

まとめ

では、Meteorは万能で同様の開発モデルを採用していくべきでしょうか? 必ずしもそうではないと思います。 まず、Meteorに限って言えば未成熟な部分もあります。特にモバイル周りはUI周りが弱かったり、Cordovaとの連携にまだ不備があったりとめんどくさい部分もあります。ただ、コレは時間が解決してくれる気もします。

そうではなく、そもそもあまり向いてないケースとしては、トランザクションが厳密なケースと、既存の連携システムが多い場合です。

トランザクションが厳密であれば信頼性の低いクライアントのDBは使えず、結局常にサーバにアクセスする以外ありません。

また、このアプローチは基本的にクライアントに合わせてサーバサイドを作る場合に適したモデルなので、すでに他システムなどでサーバサイドが存在する場合にはかえって面倒になるかもしれません。

ただ、逆に言えば厳密性が重要ではなく、プロトタイプや新規アプリを開発するには非常に向いた方法だと思うので、MBaaSとの連携含めてもうちょっと研究してきたいと思います。

そもそも、AndroidiOSを前提にしたネイティブなMeteorっぽい仕組みのが個人的には嬉しいですし。

それではHappy Hacking!

参考