昴を読んだ。

読んだ。

前職の気の置けない人たちと酒を飲んでいた時に、昔の漫画の話で盛り上がった。そのときに薦められたのが昴。天才バレエ少女の物語。

漫画でバレエの躍動感が伝わるものかな。そんな疑問を抱きながら、この漫画を読んだのだが、甘かった。この漫画はすごい。
iPadの画面からとんでもないエネルギーが飛んでくる。ページをめくるとドキっとする。端末を持つ手が震える。何回も鳥肌が立った。一気に最後まで読んだ。

今年読んだ漫画の中で一番面白かったかもしれない。ご一読をおすすめします。

昴(1) (ビッグコミックス)

昴(1) (ビッグコミックス)

MOON―昴 ソリチュード スタンディング― 9 (ビッグコミックス)

MOON―昴 ソリチュード スタンディング― 9 (ビッグコミックス)

Vue.js Tokyo v-meetup="#1"でLTしてきた、と発表からカットしたMVVMのあれこれ

Vue.js Tokyo v-meetup="#1" - connpassでLTしてきました。発表資料はこちら。

speakerdeck.com

イベント全体を通した内容や感想については以下の記事があります。

発表内容

MVVMで設計・実装するにあたって、M・V・VMの各責務を意識してコーディングしないと、ViewModelが肥大化する。というのは、Angular.jsのコントローラ、Vue.jsのVueインスタンスが気がついたら大きくなっていたという経験がある方はピンとくるのではないでしょうか。

ViewModelが肥大化する原因はいくつかあると思っていて、ざっと思いつく限りでは以下のものがあります。

  • ViewModelが揮発性の現象によって一時的に必要な状態や振る舞いを保持し続けている
  • ViewModelがModelが本来担うべきロジックを持っている
  • ViewModelがViewを参照して、その操作をおこなっている(ここでのViewはDOM要素と定義しておきます)

これら全てについて、紹介したかったのですが、時間が8分だったので、揮発性の現象とそれをMessengerパターンで解決する方法についてのみ紹介しました。ViewModelの肥大化は起こりがちな問題なので、発表後の交流のときに共感するお言葉をいただけたのがうれしかったです。

Messengerパターンとデータバインディング

スライドに書いていなくて、発表の時に話したこと。Messengerパターン、一見、変なことをやっているようにもみえますが、本質的にはデータバインディングと同じです。データバインディングはライブラリ利用者からすると、「ViewModelの状態が変わると、それがViewに反映される」ように表面では見えますが、裏では「ViewModelの状態が変わると、変更されたことを示すイベントが発火して、それをViewがハンドリングして、ViewModelの状態を取得して、表示を更新する」ということをおこなっています。Messengerパターンは、それと同じことを揮発性の現象に対しておこなっているだけです。

以下、発表で本来話すつもりだったのですが、時間の都合でカットした内容について書きます。Vue.jsとMVVMのあれこれです。

発表でカットした内容

Modelとデータフロー、設計

サーバーサイドのMVCのファットコントローラ問題でも同じですが、Modelが本来持つべきロジックをViewModelが持つことで肥大化する場合もあります。プロトタイプやサンプル、小さいアプリケーションを開発するときはよいような気がしますが、Web APIの呼び出しやエラーハンドリング、UIや通信と関係しないドメインのロジックはModelが本来担うべきです。普段のコーディングにおいて、ViewModelは「Viewからのイベントに応じて、Modelのメソッドをただ呼び出す(返り値は扱わない)」、「Modelの変更を検知して、Modelの状態を取得して、自身の状態を更新する(= データバインディングでViewに反映する)」を意識するようにしています。データの流れはV → VM → M → VM → V で一方向です。

MVVMの批判として(どこでそれを聞いたか忘れてしまったんですが)、 「MVVMは双方向データバインディングでデータの流れが一方向でなくわかりづらい。データの変更が意図しないところに反映されてつらい」といった意見を耳にします。おそらく双方向データバインディングをView・ViewModel間だけでなく、適用する範囲を広げて、ViewModelの親子間や、ViewModel・Model間、Model同士の間に適用した結果、そう感じたのではないか、と思います。
データバインディングは、View・ViewModel間では双方向(あるいは単方向)、ViewModelの親子間は親から子への単方向に留め、ViewModelとModelは上に書いた内容を意識すれば、MVVM全体として、データの流れは一方向でわかりやすいですし、意図しないところに反映されることもなくなります。

また、ロジックが移されたModelの設計をどのようにおこなうか。これは作るもの次第だとは思いますが、自分が業務でよく作る小~中規模のSPAの場合は、通信などの非同期処理をおこなうオブジェクト、その結果を格納して変更のイベントを発火するオブジェクト、各オブジェクトのエラーイベントをハンドリングして集約するオブジェクトの3つの役割に分けています。あくまで一つの例です。場合によってはFluxを適用するべきかもしれませんし、Clean Architectureを適用するべきかもしれません。
いかなるケースでもこのやり方を適用すれば良いというものはおそらくありません(当然、MVVM自体についてもそれは言えます)。どのように設計するかは、作るアプリケーションの規模や内容、関わる人数、アップデートする頻度を考慮して判断すべきことだと思います(それを考えるのがクライアントサイドのアプリケーションを作る醍醐味、やりがいのひとつのように個人的に感じています)。

ViewModelとDOM

テスタビリティやメンテナビリティの観点から、MVVMのルールでは、ViewModelがViewを参照したり、Viewの特定の実装に依存してはいけませんが、Vue.jsでViewModelに相当するVueインスタンスはView(DOM要素)への参照を持っています。

var vm = new Vue({
  el: '#example'
});
vm.$el // id属性値がexampleの要素の参照

が、Vueインスタンス自体はDOMがなくても生成でき、ViewModelが担うべき状態の保持、プレゼンテーション・ロジックや振る舞いを動かすことが可能です。例えば、以下のコードはブラウザでないJavaScript実行環境、Node.jsで動きます。

var Vue = require('vue');
var vm = new Vue({
  data: {a: 1},
  watch: {
    'a': function(val) {
      console.log(val);
    }
  }
});
vm.a = 3;

基本的にデータバインディングによって、ライブラリ利用者が記述するVueインスタンスに関係したコードはDOM要素を参照する必要はありませんが、それでもDOM要素を操作したくなるときがあります。自分の場合は以下の様なケースです。

  • 画像の遅延ロード
  • 無限スクロール
  • DOM要素でブラウザの機能検出
  • ...

これをViewModelでおこなうと、ViewModelの肥大化に繋がります。またDOM要素に依存することでテスタビリティも下がります。DOM要素に依存していても、Phantom.jsのようなへッドレスブラウザやjsdomのようなDOMエミュレートライブラリを利用してユニットテストを記述・実行することは可能ですが、ヘッドレスブラウザは起動に時間がかかるので実行コストが高く、タイミング次第でテストが通ったり通らなかったりするなど不安定です。jsdomに関しても、エミュレートライブラリなので、本来のDOM APIと異なる振る舞いをして、ハマることもあるでしょう。ということでViewModel(Vueインスタンス)のユニットテストとして考えた場合は、やはりViewModel(Vueインスタンス)は原則、DOM要素に依存しないほうがよいと思います。

解決策のひとつとして、以下のようにカスタムディレクティブを定義してDOM要素への参照やDOM操作を逃す方法があります。

<div v-foo></div>
Vue.directive(‘foo’, {
  bind: function() {
    this.el // DOM要素への参照
    this.vm.$emit // ViewModelへイベントを送る
    this.vm.$on // ViewModelからイベントを受け取る
  },
  unbind: function() {
  }
});

まとめ

Vue.js Tokyo v-meetup="#1" でLTした内容と発表でカットした内容について紹介しました。

これまで、Vue.jsを利用していて、その手軽さ、シンプルさ、他のライブラリ/フレームワークにインスパイアされた洗練されたAPIに満足していましたが、ひとつ気になっていた点が継続性でした。他のライブラリ/フレームワーク(Angular.jsやReact.js)のように企業(Google, Facebook)がバックにいるわけではなく、個人が開発しており、コミュニティの規模も他と比べれば相対的に小さいものでした。
それが現在、PHPフレームワークLaravelで採用されたことをきっかけに、コミュニティが加速度的に大きくなってきています。また、それに伴って、Vue.js本体や周辺ライブラリの開発チームの体制が整い、スポンサーに名乗りをあげる企業も出てきています。他のライブラリ/フレームワークと比較すると、どうしても相対的に規模は小さいと言わざるおえないですが、ひとつのJavaScriptライブラリの継続性としては、現在の状態でほぼ保証されているように思います。 今回のmeetupの目玉、Vue.jsの作者EvanさんとのQAで、それを再認識できたのがよかったですね。

RareJobはじめて2ヶ月経った

そういえば始めてぼちぼちどれぐらいだろうと思って、前回書いたエントリー( RareJobをはじめた - kitak.blog )を見返したら、ちょうど2ヶ月だった。

どれくらいのペースで受けているか

忙しくて週4日になった週も1, 2回あったけど、それ以外は大体、週に5~6日レッスンを受けている。
自分は、こういう英会話に限らず「週5日やるぞ!」みたいに気合いれると、気負ってしまって大概すぐにやらなくなる。何も考えずに「一回レッスンを受けたら、とりあえず次のレッスンを予約しておく」ぐらいの気楽さが継続しているコツかな、と思っている(突然予定が入ったり、めっちゃ疲れて気が向かないときはレッスン開始30分前まではキャンセルできるのも気軽さの助けになっているような気がする)。
最終的にこうありたいというイメージは持ちつつ、意識を高すぎず、低すぎずで保つのが大事。

なにか変わったか

レッスンを受け始めた当初は、なかなか英語がすぐに口から出てこなかった。頭の中で日本語の文章を浮かべてから英語にしているので、そのラグがあったり、そもそも、普段話さない言語を話す、ということによる精神的な抵抗感や障壁があったのではないか、と思っている。 最近は30分間連続で英語のやりとりをすることに慣れてきたのか、特にストレスなく、向こうの問いかけに対して、すぐに口から英語が出てくるようになった。

あとは、仕事で海外の人にソースコードを共有する機会があったときに、ソースコードのコメントやちょっとしたドキュメントが以前よりもスラスラ書けるようになっていることに気づいた。

ちょっと話が変わるが、精神的な障壁を取り払うために、RareJobとは別で、仕事中や家に帰って気が向いたら、NHKアルジャジーラの英語放送( TV Live - NHK WORLD - EnglishLive Stream - Al Jazeera English )を垂れ流しにしている。特に内容を正確に理解するつもりはなくて、生活に英語がある状態を当たり前にするのが目的。

今後の課題は

ボキャブラリーが足りないのと、文法。ボキャブラリーは高専時代に大学の編入試験対策用に買ったDUOをちまちまやっている(結局、専攻科の推薦を受けたから、5sectionくらいしかやっていなかった。ははは...)。
文法はRareJobのレッスンを受けて、気になった部分を重点的にやっている。レッスンの内容と紐付けて、有機的に学べるのでよいかもしれない、と思っている。

こんなエントリーを書いちゃったけど、今後もゆるゆる続けるぞい。

アルスラーン戦記(5) を読んだ

読んだ。アルフリード登場巻。

その他、アルスラーンいいやつだなぁ(雑)

ディジタル作法 を読んだ

大分前に買って、ずっと積んでいたが読んだ。

ディジタル作法 カーニハン先生の「情報」教室

ディジタル作法 カーニハン先生の「情報」教室

K&RのK、ブライアン・カーニハンがコンピューティングをハードウェア、ソフトウェア、通信の3つのコア技術に分類して解説してくれる。個人的には、学生時代に学んだ内容が多く、それが「点」だとすると、この本はその点と点を結ぶ「線」のように感じた。柔らかい語り口と絶妙なジョークで非常に読みやすい。

アーサー・C・クラークが定義した「クラークの三法則」の第三法則に「充分に発達した科学技術は、魔法と見分けが付かない。」というものがある。
スマートフォンの普及や最近の人工知能分野の発達などを省みて、現代のコンピューティングがまさしくそうでないかと思う。これによって生活が豊かになったと思う反面、本物の魔法のように大衆に受け取られ、アイザック・アシモフファウンデーションシリーズの初期にあるように(その作品の場合は、原子力がそれだった)技術が宗教化・権威化し、政府や企業が大衆をコントロールするのではないか、という恐怖がある。
というのは、SF小説の読み過ぎによる極端な悲観に過ぎないかもしれないが、本書でも所々でプライバシーや監視について警鐘を鳴らしている。この問題に向き合うには各自が正しい知識を身につけ備えるしかない。この時代に生きる、少なくともコンピュータに関わる仕事に就いている人にとって、読んでおかねばならない必読の一冊である。

ファウンデーション ―銀河帝国興亡史〈1〉 (ハヤカワ文庫SF)

ファウンデーション ―銀河帝国興亡史〈1〉 (ハヤカワ文庫SF)

未来のプロフィル (ハヤカワ文庫 NF 45)

未来のプロフィル (ハヤカワ文庫 NF 45)

既存のコードの理解が捗るChrome DevToolsの使い方

jQuery系ライブラリによるDOM操作が中心のプロジェクトにがっつり機能を追加する機会があった。

そのJavaScriptのコードは他の人から引き継いだコードで、一応引き継ぎ時にディレクトリ構成、設計、実装方針について共有を受けたが、それでもいざ手を入れようとすると自分自身のコードの理解が進んでおらず「えーっと...」となってしまった。

上記以外にも、長年、多くの人が触れてきたJavaScriptのコードに機能を追加する、修正するのはなかなか難しいのではないか、と思う。最初は、ちょっとしたユーザビリティの向上のために書かれたスクリプトが、気がつけば多数のDOM操作、至る所で宣言される変数、どこから実行されるか分からない関数群で無秩序に膨れ上がり、頭を抱えることになる(そうならないようにするのがウェブフロントエンジニアがいるひとつの理由ですが…)。

これらのケースでは、まずは修正、あるいは追加する機能に関連するコードを見つけて橋頭保とすることが肝要ではないだろうか。自分の場合は、Chrome DevToolsのいくつかの機能を利用し、ページに触れる、コードを動かすことで、コードの理解が捗ったので紹介したい。

ボタンが押されたら実行されるコードを特定する

「ボタンが押されたら、どの関数が実行されるんだろう」と思った時に使える方法。(「ボタンが押されたら」はあくまで例えで、あらゆる要素・イベントで汎用的に使える方法)
言い換えるとボタンの要素に登録されているイベントリスナーを知りたい。
DevToolsを開いて、Elementsタブでボタンの要素を選択する。サイドバーのEvent Listenersタブで選択した要素に関連するイベントリスナーを確認することができる。各イベントリスナーの項目には、イベントリスナーが登録されたJavaScriptのコード位置へのアンカーがある。これをクリックすることで、ボタンが押されたら実行されるコードを調べることができる。

また、ConsoleタブからコマンドラインAPIgetEventListenersを使って調べることもできる。選択している要素は$0で参照できるのでgetEventListeners($0)を自分はよく使う。

DOM操作をおこなっている箇所を特定する

「この要素、どこで変更されているんだろう」と思った時に使える方法。
DevToolsでは、DOMの変更をトリガーにBreakpointを設定することができる。Elementsタブで対象の要素を選択する。右クリックすると、Break on...というメニューがあり、さらにそこから設定したい変更内容(サブツリーの変更、属性値の変更、ノードの削除)を選ぶことができる。 Breakpointを設定して、画面に触れると、DOM操作が起きたタイミングで処理が一時停止する。これでDOM操作がJavaScriptのどの箇所で行われているか把握することができる。

XMLHttpRequestをおこなっている箇所を特定する

Networkタブを見ていて「このXHRの通信、どこでやってるんだろう」と思った時に使える方法。
DevToolsでは、XHRをトリガーにBreakpointを設定することができる。Sourcesタブを選択して、サイドバーのXHR BreakpointsでURLの部分マッチで指定する。DOM操作同様に後は通信が発生するような操作を行えば、JavaScriptのどの箇所でXHRがおこなわれているか把握することができる。

コードがminifyされていたら

コードを特定して、Sourcesタブで表示したら、minifyされていて結局わからん、ということもある。{}ボタンを押すとminifyされているコードをprettyprintしてくれる。あるいは、自身でコントロールしているスクリプトであれば、CharlesなどのLocal Debugging ProxyでminifyされていないものをLocal Proxyするとよいだろう。あるいは、sourcemapを利用する。

まとめ

Chrome DevToolsのコマンドラインAPIやBreakpointを中心に、既存のコードの理解を助けるTipsを紹介した。意外と様々なイベントをトリガーにBreakpointを設定できる。後はそのBreakpointで特定したコードを橋頭保にJavaScriptコード自体にBreakpointを設定したり、周辺のコードを読み進めていくと良い気がする。

追記

Angular.js、React.js、Vue.jsのようなフレームワーク/ライブラリを利用している場合は、DOM操作やDOM要素へのイベントリスナーの登録がフレームワーク/ライブラリに隠蔽されているので、公式が提供している開発を補助するChrome extension( Reactだったら React Developer Tools - Chrome Web Store、Vueだったら Vue.js devtools - Chrome Web Store )を導入したほうがよいでしょう。

海賊とよばれた男(7) を読んだ

読んだ。

いよいよ、物語は佳境の日章丸事件へ。実際のところどうだったかは知らないけれど、登場人物の立派さに敬服したくなる作品。