実況中継シリーズ「Vue.jsで学ぶMVVM 非同期処理 その光と闇」 Aパート

2017年3月4日に、大阪にてYAPC::Kansaiというカンファレンスが開催されました。弊社からもわたしがスピーカーとして参加しており、「Vue.jsで学ぶMVVM 非同期処理 その光と闇」という発表をしてまいりました。とても参考になる発表が非常に多く、Perlコミュニティの力を改めて感じました。また、懇親会などでも、たくさんのハッカーと議論や情報交換ができ、大変有意義でした。カンファレンスは議論や情報交換してこそですよね!

というわけで、恒例のプレゼン再現ブログ「実況中継シリーズ」を行います。長くなりすぎるので前半と後半に分けます。本日は前半のみの公開です。

導入

f:id:nkgt_chkonk:20170322104546j:plain

本日はこういう発表をします。よろしくおねがいします。

f:id:nkgt_chkonk:20170322104547j:plain

簡単に自己紹介をさせてください。さいきん会社の名前が変わって、リラクっていう名前だったのがメディロムっていう名前になったんですけど、そこで働いています。言語的にはまあだいたいこんな感じの言語で仕事や趣味の開発をしています。

Aパート

f:id:nkgt_chkonk:20170322104548j:plain

今日の発表はAパートとBパートにわかれているのですが、まずはAパートです。

f:id:nkgt_chkonk:20170322104549j:plain

まず最初に、現代のwebフロントエンドの状況ってこういう感じだと思うんですよね。

どういうことか、ってことをまずは見ていきます。

f:id:nkgt_chkonk:20170322104550j:plain

f:id:nkgt_chkonk:20170322104551j:plain

牧歌的なwebフロントエンド開発ってこんな感じだったとおもうんですよ。画面を遷移するたびに、HTML全体がサーバーサイドがらべろっと返ってくる。で、それをでろっとブラウザがレンダリングします。JSで行うことって、レンダリングされてDOMになったHTMLをいじるくらい。画面遷移すればブラウザ側で保持されてた状態とかも一旦全部リセットされて、また新しくベロっと返ってきたHTMLをでろっとレンダリングする。

f:id:nkgt_chkonk:20170322104552j:plain

これってすごくシンプルな構造で、とてもよいですよね。われわれは頭がよくないので、複雑なものよりも単純なものを相手にしたほうがバグだって減るしメンテナンスしやすいし、単純なものはよいものなんですよ。

f:id:nkgt_chkonk:20170322104553j:plain

とはいえですね、そうは問屋が降ろさないって話もあって。リッチなユーザ体験を必要とするようなものがwebブラウザ上で動く時代が来てるんですよね。

f:id:nkgt_chkonk:20170322104554j:plain

たとえばこういうやつら。チャットサービスは自分が今見てない部屋でもなにか発言があったらその部屋のところに赤丸とかでリアルタイムで新着通知来てほしいですよね。こういうサービスでどこか書き換えるたびにHTMLベロっと返ってきて状態リセットしてデロっとレンダリングしてたら、「ゆいちゃっと」の時代に逆戻りなわけですよ(ゆいちゃっとしってるひとどれくらいいますかね。あ、いますか?高齢化問題ですね)。あるいは、音楽サービスとか動画サービスですけど、あるコンテンツを再生中に、「次に視聴するコンテンツを探しに行きたい」と思って、「あなたにおすすめのコンテンツ」みたいなところのリンクをクリックしたら再生が止まって画面全体が遷移するとか困るわけです。今見てるコンテンツを再生しながら、ほかのコンテンツをブラウズできるというのはユーザー体験としてそっちのほうが絶対にいいですよね。

f:id:nkgt_chkonk:20170322104555j:plain

f:id:nkgt_chkonk:20170322104556j:plain

で、こういうときにはSPAを検討したくなりますよね。SPAって要するにクライアントサイドでルーティングとか画面書き換えとか全部やるんで、画面遷移するたびに強制的にブラウザによって状態リセットされずにすむわけです。そうすると、さっき言ったようなユーザー体験の問題がうまく解決できそうだなって思うわけです。

f:id:nkgt_chkonk:20170322104557j:plain

ただまあ、じゃあSPAに問題がないのかと言うとですね

f:id:nkgt_chkonk:20170322104558j:plain

f:id:nkgt_chkonk:20170322104559j:plain

こういう意見があるんですよね。意見があるっていうか、これわたしのツイートなんですけど。だいたいブラウザってドキュメントビューアで、GUIアプリケーションプラットフォームじゃねーわけですよ。世界にはテキストエディタ上でなんでもやってしまう集団がいるわけですけど、そういう人たちは「粋」とか「狂気」とかそういう感じのアレであって、本人たちも「技術的デモ」「遊びの一貫」みたいな感じですよね。しかし、なぜかブラウザというドキュメントビューア上でGUIアプリケーションを作ることは一般化しており、「まじかお前ら」という感じがしてくるわけです。

いいですか、声を大にしていいますが、ブラウザはそもそもドキュメントビューアで、GUIアプリケーションプラットフォームじゃねーわけですよ!!!!

f:id:nkgt_chkonk:20170322104600j:plain

これは冗談で言っているわけではないんですね。先程も言いましたが、問題は単純なほうが絶対にバグも少ないしメンテナンスも楽だし、いいわけです。

f:id:nkgt_chkonk:20170322104601j:plain

「時代はSPAやで!!!」とか言うのほんと駄目な発想で、SPAにしたら「いままでだったら多少状態が変になってもページ遷移でリセットされてたのに!」とかまあとにかくいろんな問題にぶちあたるようになるわけです。ていうか、そもそもブラウザの開発ってものすごい労力と知力をつぎ込まれているわけで、せっかくブラウザさまが画面遷移とか面倒みてくれてたのに、わざわざブラウザさまの恩恵を捨ててブラウザ作っているひとたちよりも金も時間も知力もない自分でページ遷移から実装しなおすとか、普通に狂気の沙汰なわけです。

f:id:nkgt_chkonk:20170322104602j:plain

まあとはいえですね、リッチなユーザ体験が必要になるようなサービスだとか、あるいはその他チームの技術スタック上ちゃんと合理的な理由があるとか、あるいはやんごとなき事情とか、まあ世界にはいろいろなことがある。ほんとうにいろいろなことがある……。

そういうときに、「SPAなんてやめたほうがいい!」じゃ話は進まないし価値も提供できないわけです。

f:id:nkgt_chkonk:20170322104603j:plain

で、そうなってくると今まではほとんど無視できてた、「状態管理をどうするか」っていう問題が結構重くのしかかってくるんですね。ところで、画面遷移のたびに状態がリセットされるわけではないみたいなやつ、どっかでやったことありますよね。ていうかそれって普通のGUIアプリケーションがそうですよね。そう考えると、SPAみたいなJSアプリケーションって、要するに(これも何度か言ってますが)ブラウザ上でGUIアプリケーションを作るってことでもあるんですよ。

f:id:nkgt_chkonk:20170322104604j:plain

そう考えたら、やっぱりSPAやるんだったらちゃんとGUI先輩が培ってきてくれたGUIアプリケーション・アーキテクチャの叡智を参考にすべきだとわたしは思います。要するにMVCとかMVPとかMVVMとか呼ばれるやつとかあるじゃないですか。そういうのを雑に使うんじゃなくて、きちんと「その背景にはどういう考え方があって、このパターンは何を解決しようとしていて、何を解決しようとしていないのか」を理解して、それを適用していくのが正道なのではないでしょうか。

f:id:nkgt_chkonk:20170322104607j:plain

で、このMVなんちゃらってパターンって、基本的にはPDSと呼ばれるものを実現するパターンなんですよね。PDSについてはファウラー先生が言ってますね。

PDSを実現するためにどうするかっていうと、「M」「V」「なんちゃら」で言うところの「V」と「なんちゃら」の部分で、GUIプラットフォームが提供する機能をつかって画面の描画とかイベントの反応を行います。webでいえば、DOMとcssが「V」にあたって、DOMからのイベントを拾うのが「なんちゃら」の部分だし、DOMをいじって書き換えたりする部分が「なんちゃら」の責務になるわけです。「Vとなんちゃら」はそのほかのことは一切しません。たとえばAPIとの通信だとか、「通信中かどうかを判断する」だとか、「エラーのハンドリング」だとか。そういうのはぜーーーーんぶ「M」の責務です。

そうすると、「プレゼンテーション」に関係することは全部 V と「なんちゃら」に集約して、これが「プレゼンテーション層」。モデルはその他全部をやるんだけど、ここが「ドメイン層」になるわけです。

このとき「ドメイン」と聞いて「オッDDDか!?」となるかもしれませんが、「PDS」という話をしているときの文脈で言う「ドメイン」とDDDの話をしているときの文脈でいう「ドメイン」は別のものを指しているので、今は一旦DDDから離れてください。

「えっモデルは全部やるっていうけど、じゃあモデルは神クラスになれってこと!?」とかそういう部分の話については、手前味噌で恐縮ですがわたしが以前やった発表の資料を置いておくのでそこでフォローしてください。

techblog.reraku.co.jp

techblog.reraku.co.jp

今回の発表ではMVVMについて最低限の話をしたいと思います。

f:id:nkgt_chkonk:20170322104609j:plain

さっき言った「プレゼンテーション」に関係することは全部 V と VM に集約して、これが「プレゼンテーション層」。Mはその他全部をやるんだけど、ここが「ドメイン層」になるって話を図にするとこういう感じになります。

ViewとVMがあって、それらがプレゼンテーション層。で、Modelっていう概念はいわゆるデータ・モデルだとかドメインモデルだとかRepositoryだとかusecaseとかserviceって呼ばれるものとか、そういうのすべてを内包します。ここにはデータ・モデルやドメイン・モデルが存在するので、アプリケーションの状態はここに保存されていることになります。

f:id:nkgt_chkonk:20170322104610j:plain

で、さっきもスライドにちょっと映ってましたが、これらのコンポーネントが互いにどのようにコミュニケーションするのか、それを整理し、制限することによって、コンポーネント同士が密結合することを防ぎ、プレゼンテーションとドメインを分離するわけです。

f:id:nkgt_chkonk:20170322104608j:plain

というわけで、MVVMの場合それぞれのコンポーネントがどうコミュニケーションするのかを見ていきましょう。あ、JSでMVVMやるならVue.jsがおすすめです。このあとVue.jsの話もう出てきませんが、とにかく良いフレームワークですのでJSでPDSやりたいなら試してみてほしいですね。

f:id:nkgt_chkonk:20170322104611j:plain

まず、たとえばユーザーがボタンをクリックするだとか、あるいは画面に初回アクセスしてきたとか、そういうイベントがViewから起こります。こういうイベントを、VMが拾います。

f:id:nkgt_chkonk:20170322104612j:plain

VMは、拾ったイベントに応じて、モデルを呼び出します。このとき重要なのは、ModelがVMに対して公開する操作の返り値は常にvoidである、という点です。これを守らないと、VMとMが密結合してしまい、PDSが破れがちになります。その当たりの話はまたまた手前味噌ですが、

techblog.reraku.co.jp

とか

techblog.reraku.co.jp

あたりを参照してください。

f:id:nkgt_chkonk:20170322104613j:plain

さて、VMからMのメソッドが叩かれましたが、Mには様々なコンポーネントが存在します。その中で、例えばwebAPIを叩いたり、あるいはデータ・モデルを操作したり、ドメイン・モデルを操作したりして、Mの中で状態の変化が起こります。

f:id:nkgt_chkonk:20170322104614j:plain

Mの中で起こった状態の変化を、VMがなんらかのObservableなしくみを利用して購読します。

f:id:nkgt_chkonk:20170322104615j:plain

で、MVVMフレームワークなどが用意しているであろう、データバインドの仕組みをつかって、VMはVを描画する、という流れになります。

今回は概念的に見てきましたが、もっと詳しい例を見たい場合は、何度も同じの貼って恐縮ですが techblog.reraku.co.jp あたりを参照してください。

f:id:nkgt_chkonk:20170322104616j:plain

f:id:nkgt_chkonk:20170322104617j:plain

で、ここで重要になるのが、「アプリケーションの状態」というのはすべてDomain側にあって、Presentation側は状態を画面に反映したりイベントに反応してるだけ、ということです。DOMの操作が絡んでくると、どうしてもテストがしにくくなってくるというのはみなさんご経験があるかと思いますが、「状態管理」という複雑なものを、「プレゼンテーションのくっそテスト面倒な世界」からひっぺがして、ピュアなDomain層に寄せることに成功しました。めでたしめでたしですね。

f:id:nkgt_chkonk:20170322104618j:plain

一旦Aパートのまとめです。

えー、SPAはGUIアプリケーションです。GUIアプリケーションをブラウザ上でやるとかまじで狂気の沙汰なんで、基本的には必要ないときにSPAやるのはやめましょう。死ぬぞ。とはいえ、様々な理由によりSPAを選択するのが合理的であるような状況というのはありえます。そういうときには、GUIアプリケーションのアーキテクチャ・パターンをきちんと参考にすることで、複雑化した問題に立ち向かうことができるようになるでしょう。

次回予告

さて、Aパートでは、ブラウザアプリをめぐる厳しい状況と、その状況に立ち向かうためのMVVMの概要と、より詳しい内容へのポインタを示しました。Bパートでは、わたしが現実の業務の中でSPAをMVVMで作ったときに直面した問題とその解決について見ていこうと思います。できれば今週中に公開したい。よろしくおねがいします。